Merge branch 'nightly' of github.com:Shuffle/Shuffle into nightly
@@ -1,5 +1,4 @@
|
|||||||
# Default execution environment for workers
|
# Default execution environment for workers
|
||||||
ORG_ID=Shuffle
|
|
||||||
ENVIRONMENT_NAME=Shuffle
|
ENVIRONMENT_NAME=Shuffle
|
||||||
|
|
||||||
# Sanitize liquid.py input
|
# Sanitize liquid.py input
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
name: Nightly Release
|
name: nightly-dockerbuild
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- nightly
|
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- nightly
|
||||||
|
paths:
|
||||||
|
- "**"
|
||||||
|
- "!.github/**"
|
||||||
|
- "!**.md"
|
||||||
|
- "!docker-compose.yml"
|
||||||
jobs:
|
jobs:
|
||||||
main:
|
main:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -16,29 +20,24 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- app: frontend
|
- app: frontend
|
||||||
path: frontend
|
path: frontend
|
||||||
|
version: nightly
|
||||||
experimental: true
|
experimental: true
|
||||||
- app: backend
|
- app: backend
|
||||||
path: backend
|
path: backend
|
||||||
|
version: nightly
|
||||||
experimental: true
|
experimental: true
|
||||||
- app: orborus
|
- app: orborus
|
||||||
path: functions/onprem/orborus
|
path: functions/onprem/orborus
|
||||||
|
version: nightly
|
||||||
experimental: true
|
experimental: true
|
||||||
- app: worker
|
- app: worker
|
||||||
path: functions/onprem/worker
|
path: functions/onprem/worker
|
||||||
|
version: nightly
|
||||||
experimental: true
|
experimental: true
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set version
|
|
||||||
id: set_version
|
|
||||||
run: |
|
|
||||||
if [[ ${{ github.event_name }} == 'release' ]]; then
|
|
||||||
echo "VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "VERSION=nightly-untagged-latest" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
@@ -74,9 +73,9 @@ jobs:
|
|||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
tags: |
|
tags: |
|
||||||
ghcr.io/shuffle/shuffle-${{ matrix.app }}:${{ steps.set_version.outputs.VERSION }}
|
ghcr.io/shuffle/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/shuffle-${{ matrix.app }}:${{ steps.set_version.outputs.VERSION }}
|
${{ secrets.DOCKERHUB_USERNAME }}/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
||||||
frikky/shuffle-${{ matrix.app }}:${{ steps.set_version.outputs.VERSION }}
|
frikky/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
||||||
frikky/shuffle:${{ matrix.app }}
|
frikky/shuffle:${{ matrix.app }}
|
||||||
|
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- nightly
|
- main
|
||||||
paths:
|
paths:
|
||||||
- "**"
|
- "**"
|
||||||
- "!.github/**"
|
- "!.github/**"
|
||||||
@@ -20,19 +20,19 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- app: frontend
|
- app: frontend
|
||||||
path: frontend
|
path: frontend
|
||||||
version: nightly
|
version: 2.0.2
|
||||||
experimental: true
|
experimental: true
|
||||||
- app: backend
|
- app: backend
|
||||||
path: backend
|
path: backend
|
||||||
version: nightly
|
version: 2.0.2
|
||||||
experimental: true
|
experimental: true
|
||||||
- app: orborus
|
- app: orborus
|
||||||
path: functions/onprem/orborus
|
path: functions/onprem/orborus
|
||||||
version: nightly
|
version: 2.0.2
|
||||||
experimental: true
|
experimental: true
|
||||||
- app: worker
|
- app: worker
|
||||||
path: functions/onprem/worker
|
path: functions/onprem/worker
|
||||||
version: nightly
|
version: 2.0.2
|
||||||
experimental: true
|
experimental: true
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -74,6 +74,7 @@ jobs:
|
|||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
tags: |
|
tags: |
|
||||||
ghcr.io/shuffle/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
ghcr.io/shuffle/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
||||||
|
ghcr.io/shuffle/shuffle-${{ matrix.app }}:latest
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
${{ secrets.DOCKERHUB_USERNAME }}/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
||||||
frikky/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
frikky/shuffle-${{ matrix.app }}:${{ matrix.version }}
|
||||||
frikky/shuffle:${{ matrix.app }}
|
frikky/shuffle:${{ matrix.app }}
|
||||||
|
|||||||
@@ -33,16 +33,21 @@ jobs:
|
|||||||
sudo apt-get install helm -y --no-install-recommends
|
sudo apt-get install helm -y --no-install-recommends
|
||||||
|
|
||||||
- name: Set versions
|
- name: Set versions
|
||||||
id: set_versions
|
|
||||||
run: |
|
run: |
|
||||||
if [[ ${{ github.event_name }} == 'release' ]]; then
|
if [[ ${{ github.event_name }} == 'release' ]]; then
|
||||||
CHART_VERSION="${{ github.event.release.tag_name }}"
|
TAG_NAME="${{ github.event.release.tag_name }}"
|
||||||
APP_VERSION="${{ github.event.release.tag_name }}"
|
|
||||||
|
# Remove the v prefix
|
||||||
|
VERSION=${TAG_NAME#v}
|
||||||
|
|
||||||
|
APP_VERSION="${VERSION}"
|
||||||
|
CHART_VERSION="${VERSION}"
|
||||||
else
|
else
|
||||||
CHART_VERSION="0.0.0-nightly-untagged-latest"
|
|
||||||
APP_VERSION="nightly"
|
APP_VERSION="nightly"
|
||||||
|
CHART_VERSION="0.0.0-nightly-untagged-latest"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "APP_VERSION set to ${APP_VERSION}"
|
||||||
echo "CHART_VERSION set to ${CHART_VERSION}. Validating..."
|
echo "CHART_VERSION set to ${CHART_VERSION}. Validating..."
|
||||||
|
|
||||||
# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||||
@@ -55,8 +60,8 @@ jobs:
|
|||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "CHART_VERSION=${CHART_VERSION}" >> $GITHUB_OUTPUT
|
echo "CHART_VERSION=${CHART_VERSION}" >> "$GITHUB_ENV"
|
||||||
echo "APP_VERSION=${APP_VERSION}" >> $GITHUB_OUTPUT
|
echo "APP_VERSION=${APP_VERSION}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Update helm dependencies
|
- name: Update helm dependencies
|
||||||
run: helm dependency update ./functions/kubernetes/charts/shuffle
|
run: helm dependency update ./functions/kubernetes/charts/shuffle
|
||||||
@@ -68,4 +73,4 @@ jobs:
|
|||||||
run: helm registry login ghcr.io --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }}
|
run: helm registry login ghcr.io --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Push helm chart
|
- name: Push helm chart
|
||||||
run: helm push ./functions/kubernetes/charts/shuffle-*.tgz oci://ghcr.io/shuffle/shuffle/charts
|
run: helm push ./functions/kubernetes/charts/shuffle-*.tgz oci://ghcr.io/shuffle/charts
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
name: Automation - Add all new issues to roadmap project
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
add-to-project:
|
|
||||||
name: Add issue to project
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/add-to-project@v0.5.0
|
|
||||||
with:
|
|
||||||
project-url: https://github.com/orgs/Shuffle/projects/8
|
|
||||||
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
|
|
||||||
@@ -14,16 +14,21 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
architecture: [x64, arm64]
|
architecture: [x64, arm64]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install Docker Compose
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y docker-compose
|
||||||
|
docker-compose --version
|
||||||
|
|
||||||
- name: Set up opensearch directory
|
- name: Set up opensearch directory
|
||||||
run: chmod -R 777 shuffle-database
|
run: chmod -R 777 shuffle-database
|
||||||
|
|
||||||
- name: Build the stack
|
- name: Build the stack
|
||||||
run: docker-compose up -d
|
run: docker compose up -d
|
||||||
|
|
||||||
- name: Wait for 30 seconds
|
- name: Wait for 30 seconds
|
||||||
run: sleep 30
|
run: sleep 30
|
||||||
@@ -55,7 +60,6 @@ jobs:
|
|||||||
echo "The word 'Shuffle' was not found in the response."
|
echo "The word 'Shuffle' was not found in the response."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Register a user and check the status code
|
- name: Register a user and check the status code
|
||||||
run: |
|
run: |
|
||||||
MAX_RETRIES=30
|
MAX_RETRIES=30
|
||||||
@@ -96,31 +100,36 @@ jobs:
|
|||||||
echo "User registration failed after $MAX_RETRIES attempts."
|
echo "User registration failed after $MAX_RETRIES attempts."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
- name: Run Selenium testing for frontend
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/frontend
|
||||||
|
# write some log to see the current directory
|
||||||
|
chmod +x frontend-testing.sh
|
||||||
|
./frontend-testing.sh
|
||||||
|
|
||||||
- name: Get the API key and run a health check
|
- name: Get the API key and run a health check
|
||||||
|
id: health_check
|
||||||
run: |
|
run: |
|
||||||
RESPONSE=$(curl -s -k -u admin:StrongShufflePassword321! 'https://localhost:9200/users/_search')
|
RESPONSE=$(curl -s -k -u admin:StrongShufflePassword321! 'https://localhost:9200/users/_search')
|
||||||
|
echo "Raw Response: $RESPONSE"
|
||||||
|
|
||||||
API_KEY=$(echo "$RESPONSE" | jq -r '.hits.hits[0]._source.apikey')
|
API_KEY=$(echo "$RESPONSE" | jq -r '.hits.hits[0]._source.apikey')
|
||||||
if [ -n "$API_KEY" ]; then
|
if [ -n "$API_KEY" ] && [ "$API_KEY" != "null" ]; then
|
||||||
echo "Admin API key: $API_KEY"
|
echo "Admin API key: $API_KEY"
|
||||||
|
echo "API_KEY=$API_KEY" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo "Failed to retrieve the API key for the admin user."
|
echo "Failed to retrieve the API key for the admin user."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Waiting 1 minute before sending the health API request..."
|
||||||
|
sleep 60
|
||||||
|
|
||||||
|
echo "Checking health API..."
|
||||||
HEALTH_RESPONSE=$(curl -s 'http://localhost:3001/api/v1/health?force=true' \
|
HEALTH_RESPONSE=$(curl -s 'http://localhost:3001/api/v1/health?force=true' \
|
||||||
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
|
-H "Authorization: Bearer $API_KEY")
|
||||||
-H 'Accept-Language: en-US,en;q=0.9' \
|
|
||||||
-H 'Connection: keep-alive' \
|
echo "Health API Response: $HEALTH_RESPONSE"
|
||||||
-H 'Sec-Fetch-Dest: document' \
|
|
||||||
-H 'Sec-Fetch-Mode: navigate' \
|
|
||||||
-H 'Sec-Fetch-Site: none' \
|
|
||||||
-H "Authorization: Bearer $API_KEY" \
|
|
||||||
-H 'Sec-Fetch-User: ?1' \
|
|
||||||
-H 'Upgrade-Insecure-Requests: 1' \
|
|
||||||
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36' \
|
|
||||||
-H 'sec-ch-ua: "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"' \
|
|
||||||
-H 'sec-ch-ua-mobile: ?0' \
|
|
||||||
-H 'sec-ch-ua-platform: "macOS"')
|
|
||||||
|
|
||||||
WORKFLOWS_CREATE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.create')
|
WORKFLOWS_CREATE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.create')
|
||||||
WORKFLOWS_RUN=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run')
|
WORKFLOWS_RUN=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run')
|
||||||
@@ -128,9 +137,35 @@ jobs:
|
|||||||
WORKFLOWS_RUN_STATUS=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run_status')
|
WORKFLOWS_RUN_STATUS=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run_status')
|
||||||
WORKFLOWS_DELETE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.delete')
|
WORKFLOWS_DELETE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.delete')
|
||||||
|
|
||||||
|
echo "WORKFLOWS_CREATE: $WORKFLOWS_CREATE"
|
||||||
|
echo "WORKFLOWS_RUN: $WORKFLOWS_RUN"
|
||||||
|
echo "WORKFLOWS_RUN_FINISHED: $WORKFLOWS_RUN_FINISHED"
|
||||||
|
echo "WORKFLOWS_RUN_STATUS: $WORKFLOWS_RUN_STATUS"
|
||||||
|
echo "WORKFLOWS_DELETE: $WORKFLOWS_DELETE"
|
||||||
|
|
||||||
if [ "$WORKFLOWS_CREATE" = "true" ] && [ "$WORKFLOWS_RUN" = "true" ] && [ "$WORKFLOWS_RUN_FINISHED" = "true" ] && [ "$WORKFLOWS_RUN_STATUS" = "FINISHED" ] && [ "$WORKFLOWS_DELETE" = "true" ]; then
|
if [ "$WORKFLOWS_CREATE" = "true" ] && [ "$WORKFLOWS_RUN" = "true" ] && [ "$WORKFLOWS_RUN_FINISHED" = "true" ] && [ "$WORKFLOWS_RUN_STATUS" = "FINISHED" ] && [ "$WORKFLOWS_DELETE" = "true" ]; then
|
||||||
echo "Health endpoint check was successful."
|
echo "Health endpoint check was successful."
|
||||||
|
exit 0
|
||||||
else
|
else
|
||||||
echo "Health endpoint check failed. Response did not meet expected criteria."
|
echo "Health check failed."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
notify:
|
||||||
|
needs: build
|
||||||
|
if: failure()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Send Twilio Alert
|
||||||
|
run: |
|
||||||
|
WORKFLOW_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
|
MESSAGE="🚨 Shuffle Workflow Failed!
|
||||||
|
Repository: ${{ github.repository }}
|
||||||
|
Branch: ${{ github.ref_name }}
|
||||||
|
Workflow URL: $WORKFLOW_URL"
|
||||||
|
|
||||||
|
curl -s -X POST https://api.twilio.com/2010-04-01/Accounts/${{ secrets.TWILIO_ACCOUNT_SID }}/Messages.json \
|
||||||
|
--data-urlencode "To=${{ secrets.TWILIO_TO_NUMBER }}" \
|
||||||
|
--data-urlencode "From=${{ secrets.TWILIO_FROM_NUMBER }}" \
|
||||||
|
--data-urlencode "Body=$MESSAGE" \
|
||||||
|
-u "${{ secrets.TWILIO_ACCOUNT_SID }}:${{ secrets.TWILIO_AUTH_TOKEN }}" > /dev/null
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
# A sample workflow which checks out the code, builds a container
|
|
||||||
# image using Docker and scans that image for vulnerabilities using
|
|
||||||
# Snyk. The results are then uploaded to GitHub Security Code Scanning
|
|
||||||
#
|
|
||||||
# For more examples, including how to limit scans to only high-severity
|
|
||||||
# issues, monitor images for newly disclosed vulnerabilities in Snyk and
|
|
||||||
# fail PR checks for new vulnerabilities, see https://github.com/snyk/actions/
|
|
||||||
|
|
||||||
name: Snyk Container
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- launch
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- launch
|
|
||||||
schedule:
|
|
||||||
- cron: '18 4 * * 3'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
snyk:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Build a Docker image
|
|
||||||
run: docker build -t frontend .
|
|
||||||
|
|
||||||
- name: Run Snyk to check Docker image for vulnerabilities
|
|
||||||
# Snyk can be used to break the build when it detects vulnerabilities.
|
|
||||||
# In this case we want to upload the issues to GitHub Code Scanning
|
|
||||||
continue-on-error: true
|
|
||||||
uses: snyk/actions/docker@master
|
|
||||||
env:
|
|
||||||
# In order to use the Snyk Action you will need to have a Snyk API token.
|
|
||||||
# More details in https://github.com/snyk/actions#getting-your-snyk-token
|
|
||||||
# or you can signup for free at https://snyk.io/login
|
|
||||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
||||||
with:
|
|
||||||
image: your/image-to-test
|
|
||||||
args: --file=Dockerfile
|
|
||||||
|
|
||||||
- name: Upload result to GitHub Code Scanning
|
|
||||||
uses: github/codeql-action/upload-sarif@v1
|
|
||||||
with:
|
|
||||||
sarif_file: snyk.sarif
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# A sample workflow which checks out your Infrastructure as Code Configuration files,
|
|
||||||
# such as Kubernetes, Helm & Terraform and scans them for any security issues.
|
|
||||||
# The results are then uploaded to GitHub Security Code Scanning
|
|
||||||
#
|
|
||||||
# For more examples, including how to limit scans to only high-severity issues
|
|
||||||
# and fail PR checks, see https://github.com/snyk/actions/
|
|
||||||
|
|
||||||
name: Snyk Infrastructure as Code
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- launch
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- launch
|
|
||||||
schedule:
|
|
||||||
- cron: '41 16 * * 2'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
snyk:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Run Snyk to check configuration files for security issues
|
|
||||||
# Snyk can be used to break the build when it detects security issues.
|
|
||||||
# In this case we want to upload the issues to GitHub Code Scanning
|
|
||||||
continue-on-error: true
|
|
||||||
uses: snyk/actions/iac@master
|
|
||||||
env:
|
|
||||||
# In order to use the Snyk Action you will need to have a Snyk API token.
|
|
||||||
# More details in https://github.com/snyk/actions#getting-your-snyk-token
|
|
||||||
# or you can signup for free at https://snyk.io/login
|
|
||||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
||||||
with:
|
|
||||||
# Add the path to the configuration file that you would like to test.
|
|
||||||
# For example `deployment.yaml` for a Kubernetes deployment manifest
|
|
||||||
# or `main.tf` for a Terraform configuration file
|
|
||||||
file: your-file-to-test.yaml
|
|
||||||
- name: Upload result to GitHub Code Scanning
|
|
||||||
uses: github/codeql-action/upload-sarif@v1
|
|
||||||
with:
|
|
||||||
sarif_file: snyk.sarif
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.22 as builder
|
FROM golang:1.24 as builder
|
||||||
|
|
||||||
# Add files
|
# Add files
|
||||||
RUN mkdir /app
|
RUN mkdir /app
|
||||||
@@ -14,9 +14,8 @@ ADD ./go-app/go.mod /app
|
|||||||
RUN wget -O /app_sdk/app_base.py https://raw.githubusercontent.com/Shuffle/app_sdk/refs/heads/main/shuffle_sdk/shuffle_sdk.py
|
RUN wget -O /app_sdk/app_base.py https://raw.githubusercontent.com/Shuffle/app_sdk/refs/heads/main/shuffle_sdk/shuffle_sdk.py
|
||||||
ADD ./app_gen /app_gen
|
ADD ./app_gen /app_gen
|
||||||
|
|
||||||
RUN go get -v
|
RUN go mod download
|
||||||
#RUN go mod tidy
|
RUN go mod tidy
|
||||||
#RUN go clean -modcache
|
|
||||||
|
|
||||||
# From November 2022, CGO is enabled due to packages
|
# From November 2022, CGO is enabled due to packages
|
||||||
# that we use requiring it. This is a temporary fix
|
# that we use requiring it. This is a temporary fix
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
# No extra requirements needed
|
# No extra requirements needed
|
||||||
requests
|
requests==2.32.3
|
||||||
urllib3
|
urllib3==2.3.0
|
||||||
|
liquidpy==0.8.2
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
flask[async]==3.1.0
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
PyJWT==2.10.1
|
||||||
|
cryptography==44.0.2
|
||||||
|
shufflepy==0.1.0
|
||||||
|
shuffle-sdk==0.0.25
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
urllib3==1.26.19
|
|
||||||
requests==2.31.0
|
|
||||||
MarkupSafe==2.0.1
|
|
||||||
liquidpy==0.8.1
|
|
||||||
flask[async]==2.0.2
|
|
||||||
waitress==2.1.0
|
|
||||||
#flask==1.1.2
|
|
||||||
python-dateutil==2.8.1
|
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ func fixTags(tags []string) []string {
|
|||||||
func buildImageMemory(fs billy.Filesystem, tags []string, dockerfileFolder string, downloadIfFail bool) error {
|
func buildImageMemory(fs billy.Filesystem, tags []string, dockerfileFolder string, downloadIfFail bool) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client, err := client.NewEnvClient()
|
client, err := client.NewEnvClient()
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Unable to create docker client: %s", err)
|
log.Printf("Unable to create docker client: %s", err)
|
||||||
return err
|
return err
|
||||||
@@ -473,73 +473,84 @@ func buildImage(tags []string, dockerfileLocation string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
client, err := client.NewEnvClient()
|
|
||||||
defer client.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Unable to create docker client: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[INFO] Docker Tags: %s", tags)
|
|
||||||
dockerfileSplit := strings.Split(dockerfileLocation, "/")
|
|
||||||
|
|
||||||
// Create a buffer
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
tw := tar.NewWriter(buf)
|
|
||||||
defer tw.Close()
|
|
||||||
baseDir := strings.Join(dockerfileSplit[0:len(dockerfileSplit)-1], "/")
|
|
||||||
|
|
||||||
// Builds the entire folder into buf
|
|
||||||
err = getParsedTar(tw, baseDir, "")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Tar issue: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerFileTarReader := bytes.NewReader(buf.Bytes())
|
|
||||||
buildOptions := types.ImageBuildOptions{
|
|
||||||
Remove: true,
|
|
||||||
Tags: tags,
|
|
||||||
BuildArgs: map[string]*string{},
|
|
||||||
}
|
|
||||||
//NetworkMode: "host",
|
|
||||||
|
|
||||||
httpProxy := os.Getenv("HTTP_PROXY")
|
|
||||||
if len(httpProxy) > 0 {
|
|
||||||
buildOptions.BuildArgs["HTTP_PROXY"] = &httpProxy
|
|
||||||
}
|
|
||||||
httpsProxy := os.Getenv("HTTPS_PROXY")
|
|
||||||
if len(httpProxy) > 0 {
|
|
||||||
buildOptions.BuildArgs["https_proxy"] = &httpsProxy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the actual image
|
|
||||||
imageBuildResponse, err := client.ImageBuild(
|
|
||||||
ctx,
|
|
||||||
dockerFileTarReader,
|
|
||||||
buildOptions,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the STDOUT from the build process
|
|
||||||
defer imageBuildResponse.Body.Close()
|
|
||||||
buildBuf := new(strings.Builder)
|
|
||||||
_, err = io.Copy(buildBuf, imageBuildResponse.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
if strings.Contains(buildBuf.String(), "errorDetail") {
|
|
||||||
log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), strings.Join(tags, "\n"))
|
|
||||||
return errors.New(fmt.Sprintf("Failed building %s. Check backend logs for details. Most likely means you have an old version of Docker.", strings.Join(tags, ",")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
client, err := client.NewEnvClient()
|
||||||
|
defer client.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to create docker client: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Docker Tags: %s", tags)
|
||||||
|
dockerfileSplit := strings.Split(dockerfileLocation, "/")
|
||||||
|
|
||||||
|
// Create a buffer
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
tw := tar.NewWriter(buf)
|
||||||
|
defer tw.Close()
|
||||||
|
baseDir := strings.Join(dockerfileSplit[0:len(dockerfileSplit)-1], "/")
|
||||||
|
|
||||||
|
// Builds the entire folder into buf
|
||||||
|
err = getParsedTar(tw, baseDir, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Tar issue during app build: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerFileTarReader := bytes.NewReader(buf.Bytes())
|
||||||
|
buildOptions := types.ImageBuildOptions{
|
||||||
|
Remove: true,
|
||||||
|
Tags: tags,
|
||||||
|
BuildArgs: map[string]*string{},
|
||||||
|
}
|
||||||
|
//NetworkMode: "host",
|
||||||
|
|
||||||
|
httpProxy := os.Getenv("HTTP_PROXY")
|
||||||
|
if len(httpProxy) > 0 {
|
||||||
|
buildOptions.BuildArgs["HTTP_PROXY"] = &httpProxy
|
||||||
|
}
|
||||||
|
httpsProxy := os.Getenv("HTTPS_PROXY")
|
||||||
|
if len(httpProxy) > 0 {
|
||||||
|
buildOptions.BuildArgs["https_proxy"] = &httpsProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the actual file content from dockerFileTarReader
|
||||||
|
/*
|
||||||
|
data, err := ioutil.ReadAll(dockerFileTarReader)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed reading Dockerfile TAR reader: %s", err)
|
||||||
|
} else {
|
||||||
|
log.Printf("[DEBUG] Dockerfile TAR reader content: %s", string(data))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Build the actual image
|
||||||
|
imageBuildResponse, err := client.ImageBuild(
|
||||||
|
ctx,
|
||||||
|
dockerFileTarReader,
|
||||||
|
buildOptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the STDOUT from the build process
|
||||||
|
defer imageBuildResponse.Body.Close()
|
||||||
|
buildBuf := new(strings.Builder)
|
||||||
|
_, err = io.Copy(buildBuf, imageBuildResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
if strings.Contains(buildBuf.String(), "errorDetail") {
|
||||||
|
log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), strings.Join(tags, "\n"))
|
||||||
|
return errors.New(fmt.Sprintf("Failed building %s. Check backend logs for details. Most likely means you have an old version of Docker.", strings.Join(tags, ",")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,11 +615,27 @@ func getDockerImage(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// return
|
// return
|
||||||
//}
|
//}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
var err error
|
||||||
if err != nil {
|
body := []byte{}
|
||||||
resp.WriteHeader(401)
|
//log.Printf("IMAGE REQUEST BODY: %#v", request.Body)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Failed reading body"}`))
|
if request.Body == nil || request.Body == http.NoBody {
|
||||||
return
|
// Check for the image query, otherwise we skip everything
|
||||||
|
imageQuery := request.URL.Query().Get("image")
|
||||||
|
if len(imageQuery) == 0 {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "No image query found"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body = []byte(fmt.Sprintf(`{"name": "%s"}`, imageQuery))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
body, err = ioutil.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed reading body"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This has to be done in a weird way because Datastore doesn't
|
// This has to be done in a weird way because Datastore doesn't
|
||||||
@@ -630,28 +657,48 @@ func getDockerImage(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img := image.Summary{}
|
||||||
|
img2 := image.Summary{}
|
||||||
|
tagFound := ""
|
||||||
|
tagFound2 := ""
|
||||||
|
|
||||||
|
// Old way of doing it
|
||||||
|
//alternativeNameSplit := strings.Split(version.Name, "/")
|
||||||
|
//alternativeName := version.Name
|
||||||
|
//if len(alternativeNameSplit) == 3 {
|
||||||
|
// alternativeName = strings.Join(alternativeNameSplit[1:3], "/")
|
||||||
|
//}
|
||||||
|
|
||||||
|
appname, baseAppname, appnameSplit2, err := shuffle.GetAppNameSplit(version)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed getting appname split: %s", err)
|
||||||
|
resp.WriteHeader(500)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "message": "Couldn't get the right docker image name"}`)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(version.Name) == 0 {
|
||||||
|
log.Printf("[ERROR] No image name provided for download: %s", version.Name)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "message": "No image name"}`)))
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Trying to download image: '%s'. Appname: '%s'. BaseAppname: '%s', Split2: %s", version.Name, appname, baseAppname, appnameSplit2)
|
||||||
|
|
||||||
|
alternativeName := appname
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
images, err := dockercli.ImageList(ctx, image.ListOptions{
|
images, err := dockercli.ImageList(ctx, image.ListOptions{
|
||||||
All: true,
|
All: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
img := image.Summary{}
|
|
||||||
tagFound := ""
|
|
||||||
|
|
||||||
img2 := image.Summary{}
|
|
||||||
tagFound2 := ""
|
|
||||||
|
|
||||||
alternativeNameSplit := strings.Split(version.Name, "/")
|
|
||||||
alternativeName := version.Name
|
|
||||||
if len(alternativeNameSplit) == 3 {
|
|
||||||
alternativeName = strings.Join(alternativeNameSplit[1:3], "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[INFO] Trying to download image: %s. Alt: %s", version.Name, alternativeName)
|
|
||||||
|
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
for _, tag := range image.RepoTags {
|
for _, tag := range image.RepoTags {
|
||||||
//log.Printf("[DEBUG] Tag: %s", tag)
|
if strings.Contains(tag, "<none>") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if strings.ToLower(tag) == strings.ToLower(version.Name) {
|
if strings.ToLower(tag) == strings.ToLower(version.Name) {
|
||||||
img = image
|
img = image
|
||||||
tagFound = tag
|
tagFound = tag
|
||||||
@@ -834,7 +881,7 @@ func handleRemoteDownloadApp(resp http.ResponseWriter, ctx context.Context, user
|
|||||||
type tmpapp struct {
|
type tmpapp struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
OpenAPI string `json:"openapi"`
|
OpenAPI string `json:"openapi"`
|
||||||
App string `json:"app"`
|
App string `json:"app"`
|
||||||
}
|
}
|
||||||
|
|
||||||
app := tmpapp{}
|
app := tmpapp{}
|
||||||
@@ -984,11 +1031,4 @@ func activateWorkflowAppDocker(resp http.ResponseWriter, request *http.Request)
|
|||||||
|
|
||||||
log.Printf("[INFO] User %s (%s) is activating %s. Public: %t, Shared: %t", user.Username, user.Id, app.Name, app.Public, app.Sharing)
|
log.Printf("[INFO] User %s (%s) is activating %s. Public: %t, Shared: %t", user.Username, user.Id, app.Name, app.Public, app.Sharing)
|
||||||
buildSwaggerApp(resp, []byte(openApiApp.Body), user, true)
|
buildSwaggerApp(resp, []byte(openApiApp.Body), user, true)
|
||||||
|
|
||||||
//app.Active = true
|
|
||||||
//app.Generated = true
|
|
||||||
//app, err := shuffle.SetApp(ctx, app)
|
|
||||||
|
|
||||||
//resp.WriteHeader(200)
|
|
||||||
//resp.Write([]byte(`{"success": true}`))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,109 @@
|
|||||||
module shuffle
|
module shuffle
|
||||||
|
|
||||||
go 1.22.2
|
go 1.24.0
|
||||||
|
|
||||||
|
toolchain go1.24.3
|
||||||
|
|
||||||
|
//replace github.com/frikky/schemaless => ../../../schemaless
|
||||||
//replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared
|
//replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared
|
||||||
|
|
||||||
|
//replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/datastore v1.15.0
|
cloud.google.com/go/datastore v1.20.0
|
||||||
cloud.google.com/go/storage v1.40.0
|
cloud.google.com/go/storage v1.55.0
|
||||||
github.com/basgys/goxml2json v1.1.0
|
github.com/basgys/goxml2json v1.1.0
|
||||||
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82
|
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82
|
||||||
github.com/docker/docker v27.5.0+incompatible
|
github.com/docker/docker v28.2.2+incompatible
|
||||||
github.com/frikky/kin-openapi v0.42.0
|
github.com/frikky/kin-openapi v0.42.0
|
||||||
github.com/fsouza/go-dockerclient v1.11.0
|
github.com/fsouza/go-dockerclient v1.12.1
|
||||||
github.com/ghodss/yaml v1.0.0
|
github.com/ghodss/yaml v1.0.0
|
||||||
github.com/go-git/go-billy/v5 v5.6.0
|
github.com/go-git/go-billy/v5 v5.6.2
|
||||||
github.com/go-git/go-git/v5 v5.13.0
|
github.com/go-git/go-git/v5 v5.16.1
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/h2non/filetype v1.1.3
|
github.com/h2non/filetype v1.1.3
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shuffle/shuffle-shared v0.8.0
|
github.com/shuffle/shuffle-shared v0.8.84
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.38.0
|
||||||
google.golang.org/api v0.176.1
|
google.golang.org/api v0.236.0
|
||||||
google.golang.org/grpc v1.68.1
|
google.golang.org/grpc v1.72.2
|
||||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/api v0.30.2
|
k8s.io/api v0.33.1
|
||||||
k8s.io/apimachinery v0.30.2
|
k8s.io/apimachinery v0.33.1
|
||||||
k8s.io/client-go v0.30.2
|
k8s.io/client-go v0.33.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.112.1 // indirect
|
cel.dev/expr v0.20.0 // indirect
|
||||||
cloud.google.com/go/auth v0.3.0 // indirect
|
cloud.google.com/go v0.121.1 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
cloud.google.com/go/auth v0.16.1 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||||
cloud.google.com/go/iam v1.1.7 // indirect
|
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||||
cloud.google.com/go/scheduler v1.10.6 // indirect
|
cloud.google.com/go/iam v1.5.2 // indirect
|
||||||
|
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||||
|
cloud.google.com/go/scheduler v1.11.7 // indirect
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||||
github.com/adrg/strutil v0.2.3 // indirect
|
github.com/adrg/strutil v0.3.1 // indirect
|
||||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1 // indirect
|
github.com/algolia/algoliasearch-client-go/v3 v3.31.4 // indirect
|
||||||
github.com/bitly/go-simplejson v0.5.1 // indirect
|
github.com/bitly/go-simplejson v0.5.1 // indirect
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect
|
||||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect
|
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect
|
||||||
github.com/cloudflare/circl v1.3.7 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||||
github.com/containerd/containerd v1.6.26 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/cloudflare/circl v1.6.1 // indirect
|
||||||
|
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||||
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
|
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/frikky/schemaless v0.0.13 // indirect
|
github.com/frikky/schemaless v0.0.16 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.3 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/gnostic-models v0.6.9 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/google/go-github/v28 v28.1.1 // indirect
|
github.com/google/go-github/v28 v28.1.1 // indirect
|
||||||
github.com/google/go-querystring v1.0.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/s2a-go v0.1.9 // indirect
|
||||||
github.com/google/s2a-go v0.1.7 // indirect
|
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
|
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.15.9 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/moby/go-archive v0.1.0 // indirect
|
||||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/moby/sys/user v0.1.0 // indirect
|
github.com/moby/sys/user v0.4.0 // indirect
|
||||||
github.com/moby/sys/userns v0.1.0 // indirect
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/moby/term v0.5.2 // indirect
|
github.com/moby/term v0.5.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
@@ -93,51 +111,58 @@ require (
|
|||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/opensearch-project/opensearch-go v1.1.0 // indirect
|
github.com/opensearch-project/opensearch-go v1.1.0 // indirect
|
||||||
github.com/opensearch-project/opensearch-go/v2 v2.3.0 // indirect
|
github.com/opensearch-project/opensearch-go/v2 v2.3.0 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/sashabaranov/go-openai v1.19.2 // indirect
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||||
|
github.com/sashabaranov/go-openai v1.40.1 // indirect
|
||||||
github.com/sendgrid/rest v2.6.9+incompatible // indirect
|
github.com/sendgrid/rest v2.6.9+incompatible // indirect
|
||||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible // indirect
|
github.com/sendgrid/sendgrid-go v3.16.1+incompatible // indirect
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/src-d/gcfg v1.4.0 // indirect
|
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
github.com/zeebo/errs v1.4.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.33.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.33.0 // indirect
|
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||||
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
|
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
|
||||||
golang.org/x/net v0.33.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
|
||||||
golang.org/x/oauth2 v0.19.0 // indirect
|
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||||
golang.org/x/term v0.27.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/sync v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
|
golang.org/x/term v0.32.0 // indirect
|
||||||
|
golang.org/x/text v0.25.0 // indirect
|
||||||
|
golang.org/x/time v0.11.0 // indirect
|
||||||
google.golang.org/appengine v1.6.8 // indirect
|
google.golang.org/appengine v1.6.8 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||||
google.golang.org/protobuf v1.35.2 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
k8s.io/klog/v2 v2.120.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI=
|
||||||
|
cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
@@ -7,58 +9,65 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj
|
|||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
|
cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw=
|
||||||
cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
|
cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw=
|
||||||
cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs=
|
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||||
cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w=
|
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
|
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||||
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
|
||||||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
cloud.google.com/go/datastore v1.15.0 h1:0P9WcsQeTWjuD1H14JIY7XQscIPQ4Laje8ti96IC5vg=
|
cloud.google.com/go/datastore v1.20.0 h1:NNpXoyEqIJmZFc0ACcwBEaXnmscUpcG4NkKnbCePmiM=
|
||||||
cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8=
|
cloud.google.com/go/datastore v1.20.0/go.mod h1:uFo3e+aEpRfHgtp5pp0+6M0o147KoPaYNaPAKpfh8Ew=
|
||||||
cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM=
|
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||||
cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA=
|
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||||
|
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
|
||||||
|
cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
|
||||||
|
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||||
|
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||||
|
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
|
||||||
|
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
cloud.google.com/go/scheduler v1.10.6 h1:5U8iXLoQ03qOB+ZXlAecU7fiE33+u3QiM9nh4cd0eTE=
|
cloud.google.com/go/scheduler v1.11.7 h1:zkMEJ0UbEJ3O7NwEUlKLIp6eXYv1L7wHjbxyxznajKM=
|
||||||
cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE=
|
cloud.google.com/go/scheduler v1.11.7/go.mod h1:gqYs8ndLx2M5D0oMJh48aGS630YYvC432tHCnVWN13s=
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw=
|
cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2znf0=
|
||||||
cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g=
|
cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY=
|
||||||
|
cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4=
|
||||||
|
cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI=
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
|
||||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/Microsoft/hcsshim v0.9.10 h1:TxXGNmcbQxBKVWvjvTocNb6jrPyeHlk5EiDhhgHgggs=
|
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||||
github.com/Microsoft/hcsshim v0.9.10/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
|
github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4=
|
||||||
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA=
|
||||||
github.com/adrg/strutil v0.2.3 h1:WZVn3ItPBovFmP4wMHHVXUr8luRaHrbyIuLlHt32GZQ=
|
github.com/algolia/algoliasearch-client-go/v3 v3.31.4 h1:UJhx6AhZCYf0qZygDz2c1x1+1q2q2sfzsRaQM6yswWk=
|
||||||
github.com/adrg/strutil v0.2.3/go.mod h1:+SNxbiH6t+O+5SZqIj5n/9i5yUjR+S3XXVrjEcN2mxg=
|
github.com/algolia/algoliasearch-client-go/v3 v3.31.4/go.mod h1:i7tLoP7TYDmHX3Q7vkIOL4syVse/k5VJ+k0i8WqFiJk=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
|
||||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1 h1:FP2Xtqqs/sefR5Qluygp+jVV+juXzEdJaPrZTCDLhDQ=
|
|
||||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1/go.mod h1:i7tLoP7TYDmHX3Q7vkIOL4syVse/k5VJ+k0i8WqFiJk=
|
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
@@ -81,107 +90,115 @@ github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUK
|
|||||||
github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
|
github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
|
||||||
github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow=
|
github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow=
|
||||||
github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q=
|
github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
|
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
|
||||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w=
|
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w=
|
||||||
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82 h1:9bAydALqAjBfPHd/eAiJBHnMZUYov8m2PkXVr+YGQeI=
|
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82 h1:9bAydALqAjBfPHd/eAiJBHnMZUYov8m2PkXVr+YGQeI=
|
||||||
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82/go.mod h1:tyA14J0sA3Hph4dt+AfCjPrYR13+vVodshQSM7km9qw=
|
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82/go.mod h1:tyA14J0sA3Hph4dt+AfCjPrYR13+vVodshQSM7km9qw=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
|
||||||
github.com/containerd/containerd v1.6.26 h1:VVfrE6ZpyisvB1fzoY8Vkiq4sy+i5oF4uk7zu03RaHs=
|
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||||
github.com/containerd/containerd v1.6.26/go.mod h1:I4TRdsdoo5MlKob5khDJS2EPT1l1oMNaE2MBm6FrwxM=
|
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||||
|
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
|
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g=
|
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
|
||||||
github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U=
|
|
||||||
github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug=
|
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||||
github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||||
|
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
|
||||||
|
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
|
||||||
github.com/frikky/kin-openapi v0.42.0 h1:d5Z6vnuQ6RnCCPIxZaDL+TH2ODLxT8abytOt+Zh+Kd0=
|
github.com/frikky/kin-openapi v0.42.0 h1:d5Z6vnuQ6RnCCPIxZaDL+TH2ODLxT8abytOt+Zh+Kd0=
|
||||||
github.com/frikky/kin-openapi v0.42.0/go.mod h1:ev9OZAw7Bv5p0w93j91++6a1ElPzGcCofst+kmrWsj4=
|
github.com/frikky/kin-openapi v0.42.0/go.mod h1:ev9OZAw7Bv5p0w93j91++6a1ElPzGcCofst+kmrWsj4=
|
||||||
github.com/frikky/schemaless v0.0.13 h1:ARiN9V7wr2VZXAr9JK5wvTbyPgpGrgeiL1VhR5MlgaQ=
|
github.com/frikky/schemaless v0.0.16 h1:4d2ZktB9xGsAusbbKliOI8TuriSrdIMzD/6ToY3wkz8=
|
||||||
github.com/frikky/schemaless v0.0.13/go.mod h1:mooDxY+D6weHjhKvjy3+IE9S7P4g4cpNnidkdRv/cHQ=
|
github.com/frikky/schemaless v0.0.16/go.mod h1:jT48kTcmr1q3o8i+8qe7g+eCsbwaz2Q9CjOJevQQzQs=
|
||||||
github.com/fsouza/go-dockerclient v1.11.0 h1:4ZAk6W7rPAtPXm7198EFqA5S68rwnNQORxlOA5OurCA=
|
github.com/fsouza/go-dockerclient v1.12.1 h1:FMoLq+Zhv9Oz/rFmu6JWkImfr6CBgZOPcL+bHW4gS0o=
|
||||||
github.com/fsouza/go-dockerclient v1.11.0/go.mod h1:0I3TQCRseuPTzqlY4Y3ajfsg2VAdMQoazrkxJTiJg8s=
|
github.com/fsouza/go-dockerclient v1.12.1/go.mod h1:OqsgJJcpCwqyM3JED7TdfM9QVWS5O7jSYwXxYKmOooY=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
|
||||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
|
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||||
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
|
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E=
|
github.com/go-git/go-git/v5 v5.16.1 h1:TuxMBWNL7R05tXsUGi0kh1vi4tq0WfXNLlIrAkXG1k8=
|
||||||
github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw=
|
github.com/go-git/go-git/v5 v5.16.1/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
|
||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
@@ -190,74 +207,61 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
|
||||||
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
|
github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
|
||||||
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
|
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||||
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
||||||
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
@@ -266,19 +270,17 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
|||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
|
||||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
@@ -286,19 +288,20 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
|||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
|
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||||
|
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
||||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
|
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||||
|
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
|
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
|
||||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -310,59 +313,61 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
|||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||||
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
|
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
|
||||||
github.com/opensearch-project/opensearch-go v1.1.0 h1:eG5sh3843bbU1itPRjA9QXbxcg8LaZ+DjEzQH9aLN3M=
|
github.com/opensearch-project/opensearch-go v1.1.0 h1:eG5sh3843bbU1itPRjA9QXbxcg8LaZ+DjEzQH9aLN3M=
|
||||||
github.com/opensearch-project/opensearch-go v1.1.0/go.mod h1:+6/XHCuTH+fwsMJikZEWsucZ4eZMma3zNSeLrTtVGbo=
|
github.com/opensearch-project/opensearch-go v1.1.0/go.mod h1:+6/XHCuTH+fwsMJikZEWsucZ4eZMma3zNSeLrTtVGbo=
|
||||||
github.com/opensearch-project/opensearch-go/v2 v2.3.0 h1:nQIEMr+A92CkhHrZgUhcfsrZjibvB3APXf2a1VwCmMQ=
|
github.com/opensearch-project/opensearch-go/v2 v2.3.0 h1:nQIEMr+A92CkhHrZgUhcfsrZjibvB3APXf2a1VwCmMQ=
|
||||||
github.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8=
|
github.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||||
github.com/sashabaranov/go-openai v1.19.2 h1:+dkuCADSnwXV02YVJkdphY8XD9AyHLUWwk6V7LB6EL8=
|
github.com/sashabaranov/go-openai v1.40.1 h1:bJ08Iwct5mHBVkuvG6FEcb9MDTfsXdTYPGjYLRdeTEU=
|
||||||
github.com/sashabaranov/go-openai v1.19.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
github.com/sashabaranov/go-openai v1.40.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0=
|
github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0=
|
||||||
github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
||||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fcif2i7P7wzISv1sU6DUA=
|
github.com/sendgrid/sendgrid-go v3.16.1+incompatible h1:zWhTmB0Y8XCDzeWIm2/BIt1GjJohAA0p6hVEaDtHWWs=
|
||||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
github.com/sendgrid/sendgrid-go v3.16.1+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
github.com/shuffle/shuffle-shared v0.8.84 h1:ElIMQYjKBVOiadbiGkSzt/lPU5xqaQwRxQvk9wx/xYM=
|
||||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
github.com/shuffle/shuffle-shared v0.8.84/go.mod h1:RdfNxqCPI+zU4jQKy3E/p4Io2injm7LpSKQUCDHNtLk=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||||
|
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -372,63 +377,59 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||||
|
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
|
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
|
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||||
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||||
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 h1:R/OBkMoGgfy2fLhs2QhkCI1w4HLEQX92GCcJB6SSdNk=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 h1:giGm8w67Ja7amYNfYMdme7xSp2pIxThWopw8+QP51Yk=
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8=
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0 h1:Ydage/P0fRrSPpZeCVxzjqGcI6iVmG2xb43+IR8cjqM=
|
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE=
|
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||||
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
|
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||||
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
|
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||||
go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
|
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||||
go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
|
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
|
||||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
|
||||||
go.opentelemetry.io/proto/otlp v0.11.0 h1:cLDgIBTf4lLOlztkhzAEdQsJ4Lj+i5Wc9k6Nn0K1VyU=
|
|
||||||
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
|
|
||||||
go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8=
|
|
||||||
go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
|
||||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -437,8 +438,6 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE
|
|||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -458,8 +457,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -473,27 +470,23 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
|
||||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -502,11 +495,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -518,7 +510,6 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -530,14 +521,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -548,12 +539,12 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -565,9 +556,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn
|
|||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@@ -583,14 +572,12 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK
|
|||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
@@ -599,8 +586,8 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
|||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.176.1 h1:DJSXnV6An+NhJ1J+GWtoF2nHEuqB1VNoTfnIbjNvwD4=
|
google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0=
|
||||||
google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg=
|
google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
@@ -621,95 +608,72 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
|
|||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
||||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
|
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||||
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
|
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||||
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
|
||||||
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
|
||||||
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
|
||||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
|
||||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
|
||||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
|
||||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
|
||||||
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
|
|
||||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
|
||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
|
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
|
||||||
k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
|
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
|
||||||
k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
|
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
|
||||||
k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||||
k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
|
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
|
||||||
k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
|
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
|
||||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||||
|
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||||
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
|||||||
@@ -11,17 +11,18 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"os/exec"
|
||||||
|
"net/http"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -31,11 +32,12 @@ import (
|
|||||||
"github.com/frikky/kin-openapi/openapi2conv"
|
"github.com/frikky/kin-openapi/openapi2conv"
|
||||||
"github.com/frikky/kin-openapi/openapi3"
|
"github.com/frikky/kin-openapi/openapi3"
|
||||||
|
|
||||||
//"github.com/go-git/go-billy/v5"
|
|
||||||
"github.com/go-git/go-billy/v5/memfs"
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
gitProxy "github.com/go-git/go-git/v5/plumbing/transport"
|
gitProxy "github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
|
http2 "github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
"github.com/go-git/go-git/v5/storage/memory"
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
|
||||||
// Random
|
// Random
|
||||||
@@ -46,7 +48,8 @@ import (
|
|||||||
|
|
||||||
// Web
|
// Web
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
http2 "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
//http2 "gopkg.in/src-d/go-git.v5/plumbing/transport/http"
|
||||||
|
//http2 "github.com/go-git/go-git/plumbing/transport/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is used to handle onprem vs offprem databases etc
|
// This is used to handle onprem vs offprem databases etc
|
||||||
@@ -59,6 +62,7 @@ var registryName = "registry.hub.docker.com"
|
|||||||
var runningEnvironment = "onprem"
|
var runningEnvironment = "onprem"
|
||||||
|
|
||||||
var syncUrl = "https://shuffler.io"
|
var syncUrl = "https://shuffler.io"
|
||||||
|
//var syncUrl = "http://localhost:5002"
|
||||||
|
|
||||||
type retStruct struct {
|
type retStruct struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
@@ -445,7 +449,7 @@ func checkGitProxy(cloneOptions *git.CloneOptions) *git.CloneOptions {
|
|||||||
func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) error {
|
func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) error {
|
||||||
// Returns false if there is an issue
|
// Returns false if there is an issue
|
||||||
// Use this for register
|
// Use this for register
|
||||||
err := shuffle.CheckPasswordStrength(password)
|
err := shuffle.CheckPasswordStrength(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Bad password strength: %s", err)
|
log.Printf("[WARNING] Bad password strength: %s", err)
|
||||||
return err
|
return err
|
||||||
@@ -458,8 +462,6 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
//users, err := FindUser(ctx context.Context, username string) ([]User, error) {
|
|
||||||
|
|
||||||
users, err := shuffle.FindUser(ctx, strings.ToLower(strings.TrimSpace(username)))
|
users, err := shuffle.FindUser(ctx, strings.ToLower(strings.TrimSpace(username)))
|
||||||
if err != nil && len(users) == 0 {
|
if err != nil && len(users) == 0 {
|
||||||
log.Printf("[WARNING] Failed getting user %s: %s", username, err)
|
log.Printf("[WARNING] Failed getting user %s: %s", username, err)
|
||||||
@@ -484,7 +486,6 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini)
|
|||||||
newUser.Active = true
|
newUser.Active = true
|
||||||
newUser.Orgs = []string{org.Id}
|
newUser.Orgs = []string{org.Id}
|
||||||
|
|
||||||
// FIXME - Remove this later
|
|
||||||
if role == "admin" {
|
if role == "admin" {
|
||||||
newUser.Role = "admin"
|
newUser.Role = "admin"
|
||||||
newUser.Roles = []string{"admin"}
|
newUser.Roles = []string{"admin"}
|
||||||
@@ -637,7 +638,7 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
log.Printf("[DEBUG] Successfully created the default org!")
|
log.Printf("[DEBUG] Successfully created the default org!")
|
||||||
|
|
||||||
defaultEnv := os.Getenv("ORG_ID")
|
defaultEnv := os.Getenv("ENVIRONMENT_NAME")
|
||||||
if len(defaultEnv) == 0 {
|
if len(defaultEnv) == 0 {
|
||||||
defaultEnv = "Shuffle"
|
defaultEnv = "Shuffle"
|
||||||
log.Printf("[DEBUG] Setting default environment for org to %s", defaultEnv)
|
log.Printf("[DEBUG] Setting default environment for org to %s", defaultEnv)
|
||||||
@@ -1022,6 +1023,11 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if parsedAdmin == "true" {
|
||||||
|
userInfo.Role = "admin"
|
||||||
|
userInfo.ActiveOrg.Role = "admin"
|
||||||
|
}
|
||||||
|
|
||||||
chatDisabled := false
|
chatDisabled := false
|
||||||
if os.Getenv("SHUFFLE_CHAT_DISABLED") == "true" {
|
if os.Getenv("SHUFFLE_CHAT_DISABLED") == "true" {
|
||||||
chatDisabled = true
|
chatDisabled = true
|
||||||
@@ -1084,6 +1090,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
Priorities: orgPriorities,
|
Priorities: orgPriorities,
|
||||||
Licensed: licensed,
|
Licensed: licensed,
|
||||||
ActiveApps: activatedAppIds,
|
ActiveApps: activatedAppIds,
|
||||||
|
Theme: userInfo.Theme,
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData, err := json.Marshal(returnValue)
|
returnData, err := json.Marshal(returnValue)
|
||||||
@@ -1844,6 +1851,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// return
|
// return
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] HOOKS: webhook callback: %s", request.URL.String())
|
||||||
|
|
||||||
if request.Method != "POST" {
|
if request.Method != "POST" {
|
||||||
request.Method = "POST"
|
request.Method = "POST"
|
||||||
}
|
}
|
||||||
@@ -1855,6 +1864,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
path := strings.Split(request.URL.String(), "/")
|
path := strings.Split(request.URL.String(), "/")
|
||||||
if len(path) < 4 {
|
if len(path) < 4 {
|
||||||
|
log.Printf("[DEBUG] HOOKS: Invalid webhook path: %s", request.URL.String())
|
||||||
resp.WriteHeader(403)
|
resp.WriteHeader(403)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -1870,7 +1880,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
if location[1] == "api" {
|
if location[1] == "api" {
|
||||||
if len(location) <= 4 {
|
if len(location) <= 4 {
|
||||||
log.Printf("[INFO] Couldn't handle location. Too short in webhook: %d", len(location))
|
log.Printf("[INFO] Couldn't handle location. Too short in webhook: %d", len(location))
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1887,6 +1897,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] HOOKS: Pre user agent check")
|
||||||
|
|
||||||
// Find user agent header
|
// Find user agent header
|
||||||
userAgent := request.Header.Get("User-Agent")
|
userAgent := request.Header.Get("User-Agent")
|
||||||
if strings.Contains(strings.ToLower(userAgent), "microsoftpreview") || strings.Contains(strings.ToLower(userAgent), "googlebot") {
|
if strings.Contains(strings.ToLower(userAgent), "microsoftpreview") || strings.Contains(strings.ToLower(userAgent), "googlebot") {
|
||||||
@@ -1909,8 +1921,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
//log.Printf("HookID: %s", hookId)
|
//log.Printf("HookID: %s", hookId)
|
||||||
hook, err := shuffle.GetHook(ctx, hookId)
|
hook, err := shuffle.GetHook(ctx, hookId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Failed getting hook %s (callback): %s", hookId, err)
|
log.Printf("[WARNING] HOOKS: Failed getting hook %s (callback): %s", hookId, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1922,21 +1934,21 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
//resp.WriteHeader(200)
|
//resp.WriteHeader(200)
|
||||||
//resp.Write([]byte(`{"success": true}`))
|
//resp.Write([]byte(`{"success": true}`))
|
||||||
if hook.Status == "stopped" {
|
if hook.Status == "stopped" {
|
||||||
log.Printf("[WARNING] Not running %s because hook status is stopped", hook.Id)
|
log.Printf("[WARNING] HOOKS: Not running %s because hook status is stopped", hook.Id)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "The webhook isn't running. Is it running?"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "The webhook isn't running. Is it running?"}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hook.Workflows) == 0 {
|
if len(hook.Workflows) == 0 {
|
||||||
log.Printf("[DEBUG] Not running because hook isn't connected to any workflows")
|
log.Printf("[DEBUG] HOOKS: Not running because hook isn't connected to any workflows")
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No workflows are defined"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No workflows are defined"}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if hook.Environment == "cloud" {
|
if hook.Environment == "cloud" {
|
||||||
log.Printf("[DEBUG] This should trigger in the cloud. Duplicate action allowed onprem.")
|
log.Printf("[DEBUG] HOOKS: This should trigger in the cloud. Duplicate action allowed onprem.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check auth
|
// Check auth
|
||||||
@@ -1952,7 +1964,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[DEBUG] Body data error: %s", err)
|
log.Printf("[DEBUG] HOOKS: data read error: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -1993,7 +2005,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
b, err := json.Marshal(newBody)
|
b, err := json.Marshal(newBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed newBody marshaling for webhook: %s", err)
|
log.Printf("[ERROR] HOOKS: Failed newBody marshaling for webhook: %s", err)
|
||||||
resp.WriteHeader(500)
|
resp.WriteHeader(500)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -2009,7 +2021,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(hook.Start) == 0 {
|
if len(hook.Start) == 0 {
|
||||||
log.Printf("[WARNING] No start node for hook %s - running with workflow default.", hook.Id)
|
log.Printf("[ERROR] HOOKS: No start node for hook %s - running with workflow default.", hook.Id)
|
||||||
//bodyWrapper = string(parsedBody)
|
//bodyWrapper = string(parsedBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2021,7 +2033,6 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
// OrgId: activeOrgs[0].Id,
|
// OrgId: activeOrgs[0].Id,
|
||||||
workflowExecution, executionResp, err := handleExecution(item, workflow, newRequest, hook.OrgId)
|
workflowExecution, executionResp, err := handleExecution(item, workflow, newRequest, hook.OrgId)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if hook.Version == "v2" {
|
if hook.Version == "v2" {
|
||||||
timeout := 15
|
timeout := 15
|
||||||
@@ -2056,6 +2067,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "execution_id": "%s"}`, workflowExecution.ExecutionId)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "execution_id": "%s"}`, workflowExecution.ExecutionId)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2063,6 +2075,10 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, executionResp)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, executionResp)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[ERROR] HOOKS: END OF FUNCTION FOR '%s'. IF this is reached, something went wrong.", hook.Id)
|
||||||
|
resp.WriteHeader(500)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed to run workflow. Check logs."}`))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePipelineCallback(resp http.ResponseWriter, request *http.Request) {
|
func handlePipelineCallback(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -3079,8 +3095,9 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Check whether it's in use.
|
if user.Id == app.Owner || (user.Role == "admin" && user.ActiveOrg.Id == app.ReferenceOrg) || shuffle.ArrayContains(app.Contributors, user.Id) {
|
||||||
if user.Id != app.Owner && user.Role != "admin" {
|
log.Printf("[DEBUG] Editing app %s with user %s (%s) in org %s", test.Id, user.Username, user.Id, user.ActiveOrg.Id)
|
||||||
|
} else {
|
||||||
log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name)
|
log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name)
|
||||||
resp.WriteHeader(403)
|
resp.WriteHeader(403)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "You don't have permissions to edit this app. Contact support@shuffler.io if this persists."}`))
|
resp.Write([]byte(`{"success": false, "reason": "You don't have permissions to edit this app. Contact support@shuffler.io if this persists."}`))
|
||||||
@@ -3154,7 +3171,18 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.Owner = user.Id
|
if api.Owner == "" {
|
||||||
|
api.Owner = user.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(api.ReferenceOrg) == 0 {
|
||||||
|
api.ReferenceOrg = user.ActiveOrg.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(test.Image) > 0 {
|
||||||
|
api.SmallImage = test.Image
|
||||||
|
api.LargeImage = test.Image
|
||||||
|
}
|
||||||
|
|
||||||
err = shuffle.DumpApi(basePath, api)
|
err = shuffle.DumpApi(basePath, api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -3279,6 +3307,12 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
|
|||||||
Body: string(body),
|
Body: string(body),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !shuffle.ArrayContains(api.Contributors, user.Id) {
|
||||||
|
api.Contributors = append(api.Contributors, user.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
shuffle.SetAppRevision(ctx, api)
|
||||||
|
|
||||||
log.Printf("[INFO] API LENGTH FOR %s: %d, ID: %s", api.Name, len(parsed.Body), newmd5)
|
log.Printf("[INFO] API LENGTH FOR %s: %d, ID: %s", api.Name, len(parsed.Body), newmd5)
|
||||||
// FIXME: Might cause versioning issues if we re-use the same!!
|
// FIXME: Might cause versioning issues if we re-use the same!!
|
||||||
// FIXME: Need a way to track different versions of the same app properly.
|
// FIXME: Need a way to track different versions of the same app properly.
|
||||||
@@ -3354,6 +3388,21 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
|
|||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "id": "%s"}`, api.ID)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "id": "%s"}`, api.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
org, err := shuffle.GetOrg(ctx, user.ActiveOrg.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed getting org during image build (%s): %s", user.ActiveOrg.Id, err)
|
||||||
|
} else {
|
||||||
|
imagenames := []string{
|
||||||
|
fmt.Sprintf("%s_%s", api.Name, api.AppVersion),
|
||||||
|
fmt.Sprintf("%s_%s", api.Name, api.ID),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = shuffle.DistributeAppToEnvironments(ctx, *org, imagenames)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed distributing app to environments: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an app from the app builder
|
// Creates an app from the app builder
|
||||||
@@ -3507,7 +3556,12 @@ func handleCloudJob(job shuffle.CloudSyncJob) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
redirectDomain := "localhost:5001"
|
backendPort := os.Getenv("BACKEND_PORT")
|
||||||
|
if backendPort == "" {
|
||||||
|
backendPort = "5001"
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectDomain := fmt.Sprintf("localhost:%s", backendPort)
|
||||||
redirectUrl := fmt.Sprintf("http://%s/api/v1/triggers/outlook/register", redirectDomain)
|
redirectUrl := fmt.Sprintf("http://%s/api/v1/triggers/outlook/register", redirectDomain)
|
||||||
outlookClient, _, err := shuffle.GetOutlookClient(ctx, "", hook.OauthToken, redirectUrl)
|
outlookClient, _, err := shuffle.GetOutlookClient(ctx, "", hook.OauthToken, redirectUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -3752,30 +3806,57 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if org.SyncConfig.WorkflowBackup {
|
// Check if it's 1/20 times (600 seconds - 10 min on average)
|
||||||
workflows, err := shuffle.GetAllWorkflowsByQuery(ctx, foundUser, 250, "")
|
// Only problem: May take time to sync the first time, which is annoying
|
||||||
if err != nil {
|
// This is to ensure that we don't spam the shuffle cloud servers with a lot of data
|
||||||
log.Printf("[ERROR] Failed getting backup workflows for org %s: %s", org.Id, err)
|
shouldBackupData := false
|
||||||
} else {
|
randomNumber := rand.Intn(20)
|
||||||
backupJob.Workflows = workflows
|
if randomNumber == 0 {
|
||||||
}
|
shouldBackupData = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if org.SyncConfig.AppBackup && len(org.Users) > 0 {
|
// Just to prevent it from spamming large outbound requests
|
||||||
|
if shouldBackupData {
|
||||||
apps, err := shuffle.GetPrioritizedApps(ctx, foundUser)
|
if org.SyncConfig.WorkflowBackup {
|
||||||
if err != nil {
|
workflows, err := shuffle.GetAllWorkflowsByQuery(ctx, foundUser, 250, "")
|
||||||
log.Printf("[ERROR] Failed getting backup apps for org %s: %s", org.Id, err)
|
if err != nil {
|
||||||
} else {
|
log.Printf("[ERROR] Failed getting backup workflows for org %s: %s", org.Id, err)
|
||||||
backupJob.Apps = apps
|
} else {
|
||||||
|
backupJob.Workflows = workflows
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
info, err := shuffle.GetOrgStatistics(ctx, org.Id)
|
if org.SyncConfig.AppBackup && len(org.Users) > 0 {
|
||||||
if err != nil {
|
foundUser.ActiveOrg.Id = org.Id
|
||||||
log.Printf("[ERROR] Failed getting org statistics backup for org %s: %s", org.Id, err)
|
apps, err := shuffle.GetPrioritizedApps(ctx, foundUser)
|
||||||
} else {
|
if err != nil {
|
||||||
backupJob.Stats = *info
|
log.Printf("[ERROR] Failed getting backup apps for org %s: %s", org.Id, err)
|
||||||
|
} else {
|
||||||
|
parsedApps := []shuffle.WorkflowApp{}
|
||||||
|
for _, app := range apps {
|
||||||
|
if len(app.Actions) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !app.Generated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedApps = append(parsedApps, app)
|
||||||
|
}
|
||||||
|
|
||||||
|
backupJob.Apps = parsedApps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send stats once every 10 times or so..?
|
||||||
|
// For now, just send every time
|
||||||
|
info, err := shuffle.GetOrgStatistics(ctx, org.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed getting org statistics backup for org %s: %s", org.Id, err)
|
||||||
|
} else {
|
||||||
|
backupJob.Stats = *info
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backupJobData, err := json.Marshal(backupJob)
|
backupJobData, err := json.Marshal(backupJob)
|
||||||
@@ -3812,6 +3893,7 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
|
|||||||
//log.Printf("[ERROR] Failed cloud sync job controller run for '%s': %s", respBody, err)
|
//log.Printf("[ERROR] Failed cloud sync job controller run for '%s': %s", respBody, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3843,7 +3925,7 @@ func runInitEs(ctx context.Context) {
|
|||||||
log.Printf("[INFO] Running with HTTPS proxy %s (env: HTTPS_PROXY)", httpsProxy)
|
log.Printf("[INFO] Running with HTTPS proxy %s (env: HTTPS_PROXY)", httpsProxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultEnv := os.Getenv("ORG_ID")
|
defaultEnv := os.Getenv("ENVIRONMENT_NAME")
|
||||||
if len(defaultEnv) == 0 {
|
if len(defaultEnv) == 0 {
|
||||||
defaultEnv = "Shuffle"
|
defaultEnv = "Shuffle"
|
||||||
log.Printf("[DEBUG] Setting default environment for org to %s", defaultEnv)
|
log.Printf("[DEBUG] Setting default environment for org to %s", defaultEnv)
|
||||||
@@ -3949,6 +4031,8 @@ func runInitEs(ctx context.Context) {
|
|||||||
time.Sleep(30 * time.Second)
|
time.Sleep(30 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This should ONLY run on one backend instance
|
||||||
|
|
||||||
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
|
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
|
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
|
||||||
@@ -4092,7 +4176,7 @@ func runInitEs(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//interval := int(org.SyncConfig.Interval)
|
//interval := int(org.SyncConfig.Interval)
|
||||||
interval := 15
|
interval := 30
|
||||||
if interval == 0 {
|
if interval == 0 {
|
||||||
log.Printf("[WARNING] Skipping org %s because sync isn't set (0).", org.Id)
|
log.Printf("[WARNING] Skipping org %s because sync isn't set (0).", org.Id)
|
||||||
continue
|
continue
|
||||||
@@ -4161,20 +4245,26 @@ func runInitEs(ctx context.Context) {
|
|||||||
|
|
||||||
cleanupJob := func() func() {
|
cleanupJob := func() func() {
|
||||||
return func() {
|
return func() {
|
||||||
log.Printf("[INFO] Running schedule for cleaning up or re-running unfinished workflows in %d environments.", len(environments))
|
//log.Printf("[INFO] Running schedule for cleaning up or re-running unfinished workflows in %d environments.", len(environments))
|
||||||
|
|
||||||
|
backendPort := os.Getenv("BACKEND_PORT")
|
||||||
|
if backendPort == "" {
|
||||||
|
backendPort = "5001"
|
||||||
|
}
|
||||||
|
|
||||||
for _, environment := range environments {
|
for _, environment := range environments {
|
||||||
// Allowed without PROXY management as it's localhost
|
// Allowed without PROXY management as it's localhost
|
||||||
// client := shuffle.GetExternalClient(syncUrl)
|
// client := shuffle.GetExternalClient(syncUrl)
|
||||||
|
|
||||||
httpClient := &http.Client{}
|
httpClient := &http.Client{}
|
||||||
url := fmt.Sprintf("http://localhost:5001/api/v1/environments/%s/stop", environment)
|
url := fmt.Sprintf("http://localhost:%s/api/v1/environments/%s/stop", backendPort, environment)
|
||||||
req, err := http.NewRequest(
|
req, err := http.NewRequest(
|
||||||
"GET",
|
"GET",
|
||||||
url,
|
url,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FIXME: This will stop working of the user rotates their key lol
|
||||||
req.Header.Add("Authorization", fmt.Sprintf(`Bearer %s`, parsedApikey))
|
req.Header.Add("Authorization", fmt.Sprintf(`Bearer %s`, parsedApikey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed CREATING environment request for %s: %s", environment, err)
|
log.Printf("[ERROR] Failed CREATING environment request for %s: %s", environment, err)
|
||||||
@@ -4188,14 +4278,22 @@ func runInitEs(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
respBody, err := ioutil.ReadAll(newresp.Body)
|
respBody, err := ioutil.ReadAll(newresp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed setting respbody %s", err)
|
log.Printf("[ERROR] Failed setting respbody %s for execution stop. Status: %d", err, newresp.StatusCode)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Printf("[DEBUG] Successfully ran workflow cleanup request for %s. Body: %s", environment, string(respBody))
|
|
||||||
|
|
||||||
url = fmt.Sprintf("http://localhost:5001/api/v1/environments/%s/rerun", environment)
|
if newresp.StatusCode != 200 {
|
||||||
|
if !strings.Contains(string(respBody), "is active") {
|
||||||
|
log.Printf("[WARNING] Failed stopping runs in environment %s. Status code: %d. Body: %s", environment, newresp.StatusCode, string(respBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
url = fmt.Sprintf("http://localhost:%s/api/v1/environments/%s/rerun", backendPort, environment)
|
||||||
req, err = http.NewRequest(
|
req, err = http.NewRequest(
|
||||||
"GET",
|
"GET",
|
||||||
url,
|
url,
|
||||||
@@ -4215,12 +4313,17 @@ func runInitEs(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
respBody, err = ioutil.ReadAll(newresp.Body)
|
if newresp.StatusCode != 200 {
|
||||||
if err != nil {
|
log.Printf("[WARNING] Failed rerunning environment %s. Status code: %d", environment, newresp.StatusCode)
|
||||||
log.Printf("[ERROR] Failed setting respbody %s", err)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
log.Printf("[DEBUG] Successfully ran workflow RERUN request for %s. Body: %s", environment, string(respBody))
|
|
||||||
|
//respBody, err := ioutil.ReadAll(newresp.Body)
|
||||||
|
//if err != nil {
|
||||||
|
// log.Printf("[ERROR] Failed setting respbody %s", err)
|
||||||
|
// continue
|
||||||
|
//}
|
||||||
|
|
||||||
|
//log.Printf("[DEBUG] Ran workflow RERUN request for %s with the response. Body: %s", environment, string(respBody))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4313,45 +4416,16 @@ func runInitEs(ctx context.Context) {
|
|||||||
log.Printf("[DEBUG] Skipping download of default apps as %d were found", len(workflowapps))
|
log.Printf("[DEBUG] Skipping download of default apps as %d were found", len(workflowapps))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Downloading OpenAPI data for search - EXTRA APPS")
|
|
||||||
apis := "https://github.com/shuffle/security-openapis"
|
|
||||||
|
|
||||||
// THis gets memory problems hahah
|
|
||||||
//apis := "https://github.com/APIs-guru/openapi-directory"
|
|
||||||
fs := memfs.New()
|
|
||||||
storer := memory.NewStorage()
|
|
||||||
cloneOptions := &git.CloneOptions{
|
|
||||||
URL: apis,
|
|
||||||
}
|
|
||||||
|
|
||||||
cloneOptions = checkGitProxy(cloneOptions)
|
|
||||||
|
|
||||||
_, err = git.Clone(storer, fs, cloneOptions)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERROR] Failed loading repo %s into memory: %s", apis, err)
|
|
||||||
} else if err == nil && len(workflowapps) < 10 {
|
|
||||||
log.Printf("[INFO] Finished git clone. Looking for updates to the repo.")
|
|
||||||
dir, err := fs.ReadDir("")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed reading folder: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
iterateOpenApiGithub(fs, dir, "", "")
|
|
||||||
log.Printf("[INFO] Finished downloading extra API samples")
|
|
||||||
} else {
|
|
||||||
log.Printf("[INFO] Skipping download of extra API samples as %d were found", len(workflowapps))
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.Getenv("SHUFFLE_HEALTHCHECK_DISABLED") != "true" {
|
if os.Getenv("SHUFFLE_HEALTHCHECK_DISABLED") != "true" {
|
||||||
healthcheckInterval := 30
|
healthcheckInterval := 60
|
||||||
log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval)
|
log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats, and dashboard on /health. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval)
|
||||||
job := func() {
|
job := func() {
|
||||||
// Prepare a fake http.responsewriter
|
// Prepare a fake http.responsewriter
|
||||||
resp := httptest.NewRecorder()
|
resp := httptest.NewRecorder()
|
||||||
|
|
||||||
request := http.Request{}
|
request := http.Request{}
|
||||||
// Add the "force=true" query to the fake request
|
// Add the "force=true" query to the fake request
|
||||||
request.URL, err = url.Parse("/api/v1/health/stats?force=true")
|
request.URL, err = url.Parse("/api/v1/health?force=true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed to parse test url for healthstats: %s", err)
|
log.Printf("[ERROR] Failed to parse test url for healthstats: %s", err)
|
||||||
}
|
}
|
||||||
@@ -4422,7 +4496,7 @@ func handleStopCloudSync(syncUrl string, org shuffle.Org) (*shuffle.Org, error)
|
|||||||
return &org, errors.New(fmt.Sprintf("Couldn't find any sync key to disable org %s", org.Id))
|
return &org, errors.New(fmt.Sprintf("Couldn't find any sync key to disable org %s", org.Id))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Should run cloud sync disable for org %s with URL %s and sync key %s", org.Id, syncUrl, org.SyncConfig.Apikey)
|
log.Printf("[INFO] Should run cloud sync disable for org %s with URL %s", org.Id, syncUrl)
|
||||||
|
|
||||||
client := shuffle.GetExternalClient(syncUrl)
|
client := shuffle.GetExternalClient(syncUrl)
|
||||||
req, err := http.NewRequest(
|
req, err := http.NewRequest(
|
||||||
@@ -4635,7 +4709,7 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// If you want to disable cloud sync, see previous section.
|
// If you want to disable cloud sync, see previous section.
|
||||||
if org.CloudSync {
|
if org.CloudSync {
|
||||||
log.Printf("[WARNING] Org %s is already syncing. Skip", org.Id)
|
log.Printf("[WARNING] Org %s is already syncing. Skip", org.Id)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Your org is already syncing. Nothing to set up."}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Your org is already syncing. Nothing to set up."}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -4712,6 +4786,9 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
|
|||||||
org.SyncConfig = shuffle.SyncConfig{
|
org.SyncConfig = shuffle.SyncConfig{
|
||||||
Apikey: responseData.SessionKey,
|
Apikey: responseData.SessionKey,
|
||||||
Interval: responseData.IntervalSeconds,
|
Interval: responseData.IntervalSeconds,
|
||||||
|
|
||||||
|
WorkflowBackup: true,
|
||||||
|
AppBackup: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
interval := int(responseData.IntervalSeconds)
|
interval := int(responseData.IntervalSeconds)
|
||||||
@@ -5092,8 +5169,8 @@ func initHandlers() {
|
|||||||
// Changed from workflows/streams to streams, as appengine was messing up
|
// Changed from workflows/streams to streams, as appengine was messing up
|
||||||
// This does not increase the API counter
|
// This does not increase the API counter
|
||||||
// Used by frontend
|
// Used by frontend
|
||||||
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
|
r.HandleFunc("/api/v1/streams", handleSetWorkflowExecution).Methods("POST")
|
||||||
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/streams/results", handleGetWorkflowExecutionResult).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
// Used by orborus
|
// Used by orborus
|
||||||
r.HandleFunc("/api/v1/workflows/queue", handleGetWorkflowqueue).Methods("GET", "POST")
|
r.HandleFunc("/api/v1/workflows/queue", handleGetWorkflowqueue).Methods("GET", "POST")
|
||||||
@@ -5104,7 +5181,7 @@ func initHandlers() {
|
|||||||
r.HandleFunc("/api/v1/apps/{key}/execute", executeSingleAction).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{key}/execute", executeSingleAction).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{key}/run", executeSingleAction).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{key}/run", executeSingleAction).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/categories", shuffle.GetActiveCategories).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/categories", shuffle.GetActiveCategories).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/categories/run", shuffle.RunCategoryAction).Methods("POST", "OPTIONS")
|
//r.HandleFunc("/api/v1/apps/categories/run", shuffle.RunCategoryAction).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/upload", handleAppZipUpload).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/upload", handleAppZipUpload).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{appId}/activate", activateWorkflowAppDocker).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{appId}/activate", activateWorkflowAppDocker).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{appId}/deactivate", activateWorkflowAppDocker).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{appId}/deactivate", activateWorkflowAppDocker).Methods("GET", "OPTIONS")
|
||||||
@@ -5185,6 +5262,16 @@ func initHandlers() {
|
|||||||
r.HandleFunc("/api/v1/hooks/{key}/delete", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/hooks/{key}/delete", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/hooks/{key}", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/hooks/{key}", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS")
|
||||||
|
|
||||||
|
// This structure is horrendous. Needs fixing after we got the prototype up
|
||||||
|
r.HandleFunc("/api/v1/detections", shuffle.HandleListDetectionCategories).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/detections/{detectionType}/connect", shuffle.HandleDetectionAutoConnect).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/detections/{detection_type}", shuffle.HandleGetDetectionRules).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/detections/{detection_type}/selected_rules/{action}", shuffle.HandleFolderToggle).Methods("PUT", "OPTIONS")
|
||||||
|
|
||||||
|
r.HandleFunc("/api/v1/detections/{triggerId}/selected_rules", shuffle.HandleGetSelectedRules).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/detections/{triggerId}/selected_rules/save", shuffle.HandleSaveSelectedRules).Methods("POST", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/detections/{detection_type}/{fileId}/{action}", shuffle.HandleToggleRule).Methods("PUT", "OPTIONS")
|
||||||
|
|
||||||
// OpenAPI configuration
|
// OpenAPI configuration
|
||||||
r.HandleFunc("/api/v1/verify_swagger", verifySwagger).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/verify_swagger", verifySwagger).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/verify_openapi", verifySwagger).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/verify_openapi", verifySwagger).Methods("POST", "OPTIONS")
|
||||||
@@ -5327,6 +5414,7 @@ func main() {
|
|||||||
if innerPort == "" {
|
if innerPort == "" {
|
||||||
log.Printf("[DEBUG] Running on %s:5001", hostname)
|
log.Printf("[DEBUG] Running on %s:5001", hostname)
|
||||||
log.Fatal(http.ListenAndServe(":5001", nil))
|
log.Fatal(http.ListenAndServe(":5001", nil))
|
||||||
|
os.Setenv("BACKEND_PORT", "5001")
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[DEBUG] Running on %s:%s", hostname, innerPort)
|
log.Printf("[DEBUG] Running on %s:%s", hostname, innerPort)
|
||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", innerPort), nil))
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", innerPort), nil))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
frontend:
|
frontend:
|
||||||
image: ghcr.io/shuffle/shuffle-frontend:latest
|
image: ghcr.io/shuffle/shuffle-frontend:nightly
|
||||||
container_name: shuffle-frontend
|
container_name: shuffle-frontend
|
||||||
hostname: shuffle-frontend
|
hostname: shuffle-frontend
|
||||||
ports:
|
ports:
|
||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
backend:
|
backend:
|
||||||
image: ghcr.io/shuffle/shuffle-backend:latest
|
image: ghcr.io/shuffle/shuffle-backend:nightly
|
||||||
container_name: shuffle-backend
|
container_name: shuffle-backend
|
||||||
hostname: ${BACKEND_HOSTNAME}
|
hostname: ${BACKEND_HOSTNAME}
|
||||||
# Here for debugging:
|
# Here for debugging:
|
||||||
@@ -33,7 +33,7 @@ services:
|
|||||||
- SHUFFLE_FILE_LOCATION=/shuffle-files
|
- SHUFFLE_FILE_LOCATION=/shuffle-files
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
orborus:
|
orborus:
|
||||||
image: ghcr.io/shuffle/shuffle-orborus:latest
|
image: ghcr.io/shuffle/shuffle-orborus:nightly
|
||||||
container_name: shuffle-orborus
|
container_name: shuffle-orborus
|
||||||
hostname: shuffle-orborus
|
hostname: shuffle-orborus
|
||||||
networks:
|
networks:
|
||||||
@@ -53,15 +53,15 @@ services:
|
|||||||
- SHUFFLE_PASS_WORKER_PROXY=${SHUFFLE_PASS_WORKER_PROXY}
|
- SHUFFLE_PASS_WORKER_PROXY=${SHUFFLE_PASS_WORKER_PROXY}
|
||||||
- SHUFFLE_PASS_APP_PROXY=${SHUFFLE_PASS_APP_PROXY}
|
- SHUFFLE_PASS_APP_PROXY=${SHUFFLE_PASS_APP_PROXY}
|
||||||
- SHUFFLE_STATS_DISABLED=true
|
- SHUFFLE_STATS_DISABLED=true
|
||||||
- SHUFFLE_WORKER_SCALE=run
|
|
||||||
- SHUFFLE_LOGS_DISABLED=true
|
- SHUFFLE_LOGS_DISABLED=true
|
||||||
- SHUFFLE_WORKER_IMAGE=ghcr.io/shuffle/shuffle-worker:latest
|
- SHUFFLE_SWARM_CONFIG=run
|
||||||
|
- SHUFFLE_WORKER_IMAGE=ghcr.io/shuffle/shuffle-worker:nightly
|
||||||
env_file: .env
|
env_file: .env
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
- seccomp:unconfined
|
- seccomp:unconfined
|
||||||
opensearch:
|
opensearch:
|
||||||
image: opensearchproject/opensearch:2.14.0
|
image: opensearchproject/opensearch:3.0.0
|
||||||
hostname: shuffle-opensearch
|
hostname: shuffle-opensearch
|
||||||
container_name: shuffle-opensearch
|
container_name: shuffle-opensearch
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
SERVER_URL="http://localhost:3000"
|
||||||
|
|
||||||
|
declare -a Routes=($(grep -oP '(?<=path=")[^"]*' src/App.jsx | grep -E '^[a-zA-Z0-9/_:-]+$' | grep -vE '^/$'))
|
||||||
|
|
||||||
|
for i in "${!Routes[@]}"; do
|
||||||
|
Routes[$i]="${Routes[$i]#/}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# # Add all tab routes and unique routes here
|
||||||
|
Routes+=(
|
||||||
|
'workflows?tab=org_workflows'
|
||||||
|
'workflows?tab=my_workflows'
|
||||||
|
'workflows?tab=all_workflows'
|
||||||
|
'apps/gmail'
|
||||||
|
'apis/gmail'
|
||||||
|
'apps?tab=my_apps'
|
||||||
|
'apps?tab=all_apps'
|
||||||
|
'search?tab=org_apps'
|
||||||
|
'search?tab=my_apps'
|
||||||
|
'search?tab=workflows'
|
||||||
|
'search?tab=docs'
|
||||||
|
'search?tab=creators'
|
||||||
|
'search?tab=discord'
|
||||||
|
"admin?tab=organization"
|
||||||
|
"admin?tab=users"
|
||||||
|
"admin?tab=app_auth"
|
||||||
|
"admin?tab=datastore"
|
||||||
|
"admin?tab=files"
|
||||||
|
"admin?tab=triggers"
|
||||||
|
"admin?tab=locations"
|
||||||
|
"admin?tab=tenants"
|
||||||
|
"admin?admin_tab=org_config"
|
||||||
|
"admin?admin_tab=sso"
|
||||||
|
"admin?admin_tab=notifications"
|
||||||
|
"admin?admin_tab=billingstats"
|
||||||
|
"admin?admin_tab=branding(beta)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stop frontend container so it test unpushed changes
|
||||||
|
docker stop shuffle-frontend
|
||||||
|
|
||||||
|
# # Install all frontend dependencies
|
||||||
|
yarn add selenium-webdriver --dev && yarn install
|
||||||
|
echo "Starting frontend..."
|
||||||
|
|
||||||
|
BROWSER=none yarn start &
|
||||||
|
SERVER_PID=$!
|
||||||
|
echo "Frontend started with PID: $SERVER_PID"
|
||||||
|
|
||||||
|
echo "Waiting for 1 minute to ensure the server is fully up..."
|
||||||
|
sleep 60
|
||||||
|
|
||||||
|
echo "Server is up! Starting Selenium tests..."
|
||||||
|
|
||||||
|
echo "Starting frontend tests..."
|
||||||
|
node selenium-test.js "$SERVER_URL" "${Routes[@]}"
|
||||||
|
|
||||||
|
TEST_EXIT_CODE=$?
|
||||||
|
|
||||||
|
if [[ $TEST_EXIT_CODE -ne 0 ]]; then
|
||||||
|
echo "Selenium tests failed. Exiting..."
|
||||||
|
kill $SERVER_PID
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
kill $SERVER_PID
|
||||||
|
echo "Testing complete. See above logs for errors if any."
|
||||||
|
|
||||||
|
# Starting shuffle-frontend container
|
||||||
|
echo "Starting shuffle-frontend container..."
|
||||||
|
docker start shuffle-frontend
|
||||||
|
echo "shuffle-frontend started successfully."
|
||||||
|
exit 0
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@uiw/codemirror-themes": "^4.21.9",
|
"@uiw/codemirror-themes": "^4.21.9",
|
||||||
"@uiw/react-codemirror": "^4.21.21",
|
"@uiw/react-codemirror": "^4.21.21",
|
||||||
"algoliasearch": "^4.8.3",
|
"algoliasearch": "^4.8.3",
|
||||||
"class-transformer": "^0.2.0",
|
"class-transformer": "^0.5.1",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"cpx": "^1.5.0",
|
"cpx": "^1.5.0",
|
||||||
"create-react-app": "^5.0.1",
|
"create-react-app": "^5.0.1",
|
||||||
@@ -128,6 +128,7 @@
|
|||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"promise-window": "^1.2.1",
|
"promise-window": "^1.2.1",
|
||||||
|
"selenium-webdriver": "^4.29.0",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="45" height="56" viewBox="0 0 45 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.866 31.366L22.2583 37.366L13.3454 52.8036L11.2901 46.9667C10.9625 46.0363 10.0053 45.4837 9.03569 45.6651L2.95314 46.8036L11.866 31.366Z" stroke="#2BC07E" stroke-width="2"/>
|
||||||
|
<path d="M33.759 31.366L23.3667 37.366L32.2796 52.8036L34.3349 46.9667C34.6625 46.0363 35.6197 45.4837 36.5893 45.6651L42.6719 46.8036L33.759 31.366Z" stroke="#2BC07E" stroke-width="2"/>
|
||||||
|
<path d="M18.6381 6.27038C20.6383 3.8382 24.3617 3.8382 26.3619 6.27038L26.7961 6.79841C28.1024 8.38685 30.0411 9.32049 32.0974 9.35141L32.781 9.36168C35.9296 9.40902 38.2511 12.3201 37.5966 15.4003L37.4546 16.069C37.0271 18.0807 37.5059 20.1786 38.7639 21.8056L39.182 22.3464C41.1082 24.8376 40.2796 28.4677 37.4634 29.8765L36.852 30.1823C35.0127 31.1024 33.671 32.7847 33.1833 34.7826L33.0212 35.4468C32.2744 38.5059 28.9197 40.1215 26.0624 38.798L25.442 38.5106C23.5759 37.6463 21.4241 37.6463 19.558 38.5106L18.9376 38.798C16.0803 40.1215 12.7256 38.5059 11.9788 35.4468L11.8167 34.7826C11.329 32.7847 9.98734 31.1024 8.14805 30.1823L7.53663 29.8765C4.72036 28.4677 3.89182 24.8376 5.81795 22.3464L6.23611 21.8056C7.49405 20.1786 7.97288 18.0807 7.54544 16.069L7.40335 15.4003C6.74887 12.3201 9.07037 9.40902 12.219 9.36168L12.9026 9.35141C14.9589 9.32049 16.8976 8.38685 18.2039 6.79841L17.4316 6.16323L18.2039 6.79841L18.6381 6.27038Z" fill="#2F2F2F" stroke="#2BC07E" stroke-width="2"/>
|
||||||
|
<path d="M30.5 18.5L21 28L16 23" stroke="#2BC07E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="54" height="52" viewBox="0 0 54 52" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M37.9999 31.4723C38.007 34.1853 37.3731 36.8617 36.1499 39.2834C34.6996 42.1853 32.47 44.6261 29.7108 46.3324C26.9517 48.0387 23.7719 48.9432 20.5277 48.9444C17.9537 48.9512 15.4126 48.3809 13.0908 47.2778C12.8499 47.1634 12.5744 47.1419 12.3214 47.2262L2.89737 50.3675C2.11561 50.6281 1.37187 49.8844 1.63246 49.1026L4.77381 39.6786C4.85812 39.4256 4.83665 39.1501 4.72223 38.9092C3.6191 36.5874 3.04884 34.0463 3.05555 31.4723C3.05681 28.2281 3.96125 25.0483 5.66758 22.2892C7.37391 19.53 9.81473 17.3004 12.7166 15.8501C15.1383 14.6269 17.8147 13.993 20.5277 14.0001H21.5555C25.84 14.2364 29.8868 16.0448 32.921 19.079C35.9552 22.1132 37.7636 26.16 37.9999 30.4445V31.4723Z" stroke="#4FB1E8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M39 32L38.0926 33.7823C38.6627 34.0726 39.3373 34.0726 39.9074 33.7823L39 32ZM39 32C39.9074 33.7823 39.9079 33.782 39.9085 33.7817L39.91 33.781L39.9136 33.7791L39.9239 33.7739L39.9562 33.7571C39.9829 33.7432 40.0199 33.7237 40.0664 33.6989C40.1593 33.6492 40.2906 33.5778 40.4547 33.4853C40.7826 33.3004 41.2432 33.0306 41.7925 32.6811C42.8869 31.9846 44.3541 30.9586 45.8304 29.6433C48.7043 27.083 52 23.078 52 18V8.2C52 7.37067 51.4882 6.62739 50.7134 6.33156L39.7134 2.13156C39.254 1.95615 38.746 1.95615 38.2866 2.13156L27.2866 6.33156C26.5118 6.62739 26 7.37067 26 8.2V18C26 23.078 29.2957 27.083 32.1696 29.6433C33.6459 30.9586 35.1131 31.9846 36.2075 32.6811C36.7568 33.0306 37.2174 33.3004 37.5453 33.4853C37.7094 33.5778 37.8407 33.6492 37.9336 33.6989C37.9801 33.7237 38.0171 33.7432 38.0438 33.7571L38.0761 33.7739L38.0864 33.7791L38.09 33.781L38.0915 33.7817C38.0921 33.782 38.0926 33.7823 39 32Z" fill="#2F2F2F" stroke="#2F2F2F" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M40.1819 30.1501C39.6936 30.4608 39.2864 30.6997 39 30.8615C38.7136 30.6997 38.3064 30.4608 37.8181 30.1501C36.8185 29.5139 35.4896 28.5832 34.1652 27.4033C31.4771 25.0085 29 21.761 29 18V8.8886L39 5.07041L49 8.8886V18C49 21.761 46.5229 25.0085 43.8348 27.4033C42.5104 28.5832 41.1815 29.5139 40.1819 30.1501Z" stroke="#4FB1E8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.2326 41.4787H19.2326L19.2326 41.47C19.2313 40.1671 19.6607 38.9 20.4546 37.865C21.2485 36.8301 22.3625 36.0851 23.6242 35.7458C24.8858 35.4065 26.2244 35.4919 27.4325 35.9887C28.6405 36.4855 29.6503 37.3659 30.3056 38.4931L30.5302 38.8796L30.9393 38.6995C33.4578 37.591 35.237 36.1436 36.3734 34.1074C37.5026 32.084 37.9652 29.5351 37.9652 26.2827V19.274C37.9652 14.5199 36.6216 10.455 34.1879 7.56945C31.7474 4.6759 28.2394 3.00436 24.0012 3.00436C19.7629 3.00436 16.2549 4.67653 13.8145 7.57034C11.3808 10.4561 10.0371 14.521 10.0371 19.274V27.4501C10.0367 27.7819 9.90438 28.1002 9.66889 28.3351C9.43337 28.5701 9.11382 28.7025 8.78025 28.703H6.43988C4.86506 28.7013 3.35543 28.0765 2.242 26.966C1.1287 25.8556 0.502381 24.3503 0.5 22.7803V20.4447C0.501784 18.874 1.12781 17.3678 2.24116 16.2566C3.35447 15.1454 4.86421 14.5199 6.43943 14.5174C6.43964 14.5174 6.43985 14.5174 6.44006 14.5174L7.55861 14.5174H7.96354L8.04769 14.1213C9.77814 5.97693 15.6661 0.5 24.0012 0.5C32.3361 0.5 38.2218 5.97684 39.9523 14.1213L40.0365 14.5174H40.4414L41.5599 14.5174C41.5602 14.5174 41.5604 14.5174 41.5606 14.5174C43.1354 14.5199 44.6448 15.1451 45.7581 16.2558C46.8714 17.3667 47.4977 18.8724 47.5 20.4428V22.7778C47.4983 24.3483 46.8722 25.8543 45.7588 26.9652C44.6453 28.0762 43.1353 28.7013 41.5601 28.703H40.8371H40.3532L40.3374 29.1866C40.2503 31.8522 39.354 34.4287 37.7668 36.5749C36.1796 38.7212 33.9764 40.3361 31.4486 41.2057L31.1171 41.3197L31.1114 41.6704C31.0859 43.2413 30.436 44.7381 29.3042 45.8313C28.1724 46.9246 26.6514 47.5247 25.0758 47.4992C23.5002 47.4738 21.9995 46.8249 20.9038 45.6957C19.8081 44.5666 19.2071 43.0496 19.2326 41.4787ZM21.745 41.4701V41.4705C21.745 42.1473 21.9461 42.8087 22.3228 43.3712C22.6995 43.9337 23.2348 44.3719 23.8609 44.6306C24.4869 44.8894 25.1758 44.9571 25.8403 44.8252C26.5049 44.6933 27.1154 44.3677 27.5948 43.8895C28.0741 43.4112 28.4007 42.8017 28.533 42.138C28.6654 41.4743 28.5974 40.7864 28.3379 40.1613C28.0784 39.5362 27.639 39.0021 27.0754 38.6264C26.5119 38.2507 25.8495 38.0502 25.172 38.0502H25.1716C24.2634 38.051 23.3923 38.4112 22.7498 39.0523C22.1072 39.6934 21.7457 40.563 21.745 41.4701ZM40.4776 25.7009V26.2009H40.9776H41.5607C42.4693 26.2009 43.341 25.841 43.9842 25.1999C44.6273 24.5587 44.9892 23.6887 44.99 22.781V22.7806V20.4444C44.99 19.5368 44.6288 18.6665 43.9861 18.0248C43.3435 17.3831 42.4721 17.0225 41.5634 17.0218H41.563H40.9776H40.4776V17.5218V25.7009ZM3.01237 22.7806L3.01237 22.7815C3.01382 23.6881 3.37566 24.557 4.01816 25.1975L4.37117 24.8434L4.01816 25.1975C4.66062 25.838 5.53122 26.1979 6.43894 26.1986H6.43934H7.02473H7.52473V25.6986V17.5218V17.0218H7.02473H6.43934H6.43894C5.53027 17.0225 4.65884 17.3831 4.01622 18.0248C3.37357 18.6665 3.01237 19.5368 3.01237 20.4444L3.01237 22.7806Z" fill="#FF8544" stroke="#2F2F2F"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="65" height="45" viewBox="0 0 65 45" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M28.5445 38.9971V36.0579C28.5445 34.4989 27.9252 33.0037 26.8228 31.9013C25.7204 30.7989 24.2253 30.1796 22.6662 30.1796H10.9096C9.35055 30.1796 7.85537 30.7989 6.75297 31.9013C5.65057 33.0037 5.03125 34.4989 5.03125 36.0579V38.9971" stroke="#806BFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M16.7885 25.8205C20.035 25.8205 22.6668 23.1887 22.6668 19.9422C22.6668 16.6957 20.035 14.0638 16.7885 14.0638C13.542 14.0638 10.9102 16.6957 10.9102 19.9422C10.9102 23.1887 13.542 25.8205 16.7885 25.8205Z" stroke="#806BFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M1 43.9362H32.575" stroke="#806BFF" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M16.5742 8.16418V5C16.5742 2.79086 18.3651 1 20.5742 1H59.5742C61.7834 1 63.5742 2.79086 63.5742 5V29C63.5742 31.2091 61.7834 33 59.5742 33H33.3907" stroke="#806BFF" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="66" height="28" viewBox="0 0 66 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.25391 27.1562C5.13411 27.0521 3.82552 27 2.32812 27H0.785156L9.28125 3.19141C9.65885 2.1237 9.84766 1.50521 9.84766 1.33594C9.84766 1.15365 9.84115 1.04297 9.82812 1.00391L9.84766 0.964844C10.694 1.00391 11.5924 1.02344 12.543 1.02344C13.3242 1.02344 14.2617 1.01042 15.3555 0.984375L15.375 1.02344C15.349 1.07552 15.3359 1.14714 15.3359 1.23828C15.3359 1.48568 15.5312 2.14323 15.9219 3.21094L24.5938 27.0586C24.3333 27.0456 24.0273 27.0391 23.6758 27.0391C23.6758 27.0391 23.3372 27.026 22.6602 27C22.3346 27 22.0417 27 21.7812 27H18.7539L16.918 21.375H8.08984L6.25391 27.1562ZM15.3945 16.6875L12.4453 7.60547L9.57422 16.6875H15.3945ZM27.3867 0.886719C29.1966 0.652344 31.0521 0.535156 32.9531 0.535156C36.4948 0.535156 39.1836 1.36849 41.0195 3.03516C42.8685 4.6888 43.793 7.16927 43.793 10.4766C43.793 13.4323 42.7839 15.7695 40.7656 17.4883C38.8776 19.1029 36.4492 19.9102 33.4805 19.9102C33.1419 19.9102 32.7708 19.8906 32.3672 19.8516V27H27.3867V0.886719ZM33.5391 5.24219C33.1484 5.24219 32.7578 5.25521 32.3672 5.28125V15.5547C32.7839 15.6068 33.2917 15.6328 33.8906 15.6328C34.4896 15.6328 35.1146 15.5091 35.7656 15.2617C36.4167 15.0013 36.9635 14.6432 37.4062 14.1875C38.3307 13.237 38.793 11.987 38.793 10.4375C38.793 6.97396 37.0417 5.24219 33.5391 5.24219ZM48.4023 0.945312C49.7044 0.997396 50.4922 1.02344 50.7656 1.02344H52.1719C52.862 1.02344 53.4154 0.971354 53.832 0.867188L53.8125 27H48.4023V0.945312ZM59.9258 27C60.043 26.2057 60.1016 25.5026 60.1016 24.8906C60.1016 24.2786 60.0951 23.862 60.082 23.6406C60.082 23.4062 60.0755 23.1784 60.0625 22.957C60.0495 22.7357 60.0365 22.5273 60.0234 22.332L59.9648 21.8438H65.6289C65.5898 22.3385 65.5703 22.7422 65.5703 23.0547L65.5312 23.875C65.5312 24.1224 65.5312 24.5911 65.5312 25.2812C65.5312 25.9583 65.5638 26.5312 65.6289 27H59.9258Z" fill="#2BC07E"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.9263 14.5851V13.0757C8.9263 12.275 9.24436 11.5071 9.81052 10.941C10.3767 10.3748 11.1445 10.0568 11.9452 10.0568H17.983C18.7837 10.0568 19.5516 10.3748 20.1177 10.941C20.6839 11.5071 21.002 12.275 21.002 13.0757V14.5851" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14.9635 7.03783C13.2962 7.03783 11.9446 5.68621 11.9446 4.01891C11.9446 2.35161 13.2962 1 14.9635 1C16.6308 1 17.9824 2.35161 17.9824 4.01891C17.9824 5.68621 16.6308 7.03783 14.9635 7.03783Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M0.99923 12.887V11.6292C0.99923 10.9619 1.26428 10.3221 1.73608 9.85025C2.20788 9.37846 2.84777 9.1134 3.51499 9.1134L7.98047 9.1134" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.03111 6.59763C4.6417 6.59763 3.51535 5.47128 3.51535 4.08186C3.51535 2.69245 4.6417 1.5661 6.03111 1.5661C7.42053 1.5661 8.54688 2.69245 8.54688 4.08186C8.54688 5.47128 7.42053 6.59763 6.03111 6.59763Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.9263 14.5851V13.0757C8.9263 12.275 9.24436 11.5071 9.81052 10.941C10.3767 10.3748 11.1445 10.0568 11.9452 10.0568H17.983C18.7837 10.0568 19.5516 10.3748 20.1177 10.941C20.6839 11.5071 21.002 12.275 21.002 13.0757V14.5851" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14.9635 7.03783C13.2962 7.03783 11.9446 5.68621 11.9446 4.01891C11.9446 2.35161 13.2962 1 14.9635 1C16.6308 1 17.9824 2.35161 17.9824 4.01891C17.9824 5.68621 16.6308 7.03783 14.9635 7.03783Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M0.99923 12.887V11.6292C0.99923 10.9619 1.26428 10.3221 1.73608 9.85025C2.20788 9.37846 2.84777 9.1134 3.51499 9.1134L7.98047 9.1134" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.03111 6.59763C4.6417 6.59763 3.51535 5.47128 3.51535 4.08186C3.51535 2.69245 4.6417 1.5661 6.03111 1.5661C7.42053 1.5661 8.54688 2.69245 8.54688 4.08186C8.54688 5.47128 7.42053 6.59763 6.03111 6.59763Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,7 @@
|
|||||||
|
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.3214 5H11.4351H12.5488" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<rect x="0.501953" y="0.5" width="15" height="19" rx="1.5" stroke="#9E9E9E"/>
|
||||||
|
<path d="M3.63903 12H12.5488" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.63903 15.6666H12.5488" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.3214 8.33331H11.4351H12.5488" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 590 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.3214 5H11.4351H12.5488" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<rect x="0.501953" y="0.5" width="15" height="19" rx="1.5" stroke="#FF8544"/>
|
||||||
|
<path d="M3.63903 12H12.5488" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.63903 15.6666H12.5488" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.3214 8.33331H11.4351H12.5488" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 590 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.502 8.50003L17.502 8.50133C17.5052 9.74245 17.2152 10.9668 16.6557 12.0746L16.6547 12.0765C15.9906 13.4052 14.9698 14.5228 13.7064 15.3041C12.4431 16.0853 10.9872 16.4995 9.50176 16.5L9.50065 16.5C8.25953 16.5033 7.0352 16.2133 5.92738 15.6537C5.80838 15.5936 5.67031 15.5835 5.54384 15.6257L0.792523 17.2095L2.37629 12.4581C2.41845 12.3317 2.40836 12.1936 2.34825 12.0746C1.78869 10.9668 1.49872 9.74245 1.50195 8.50133L1.50195 8.50022C1.50253 7.01482 1.91665 5.55891 2.69792 4.29556C3.4792 3.03222 4.59678 2.01134 5.92548 1.34728L5.92548 1.34728L5.92738 1.34633C7.0352 0.786764 8.25953 0.496791 9.50065 0.500028H9.50195H9.98796C11.9444 0.611298 13.7917 1.43858 15.1775 2.82444C16.5634 4.21031 17.3907 6.05759 17.502 8.01402L17.502 8.50003Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 925 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.502 8.50003L17.502 8.50133C17.5052 9.74245 17.2152 10.9668 16.6557 12.0746L16.6547 12.0765C15.9906 13.4052 14.9698 14.5228 13.7064 15.3041C12.4431 16.0853 10.9872 16.4995 9.50176 16.5L9.50065 16.5C8.25953 16.5033 7.0352 16.2133 5.92738 15.6537C5.80838 15.5936 5.67031 15.5835 5.54384 15.6257L0.792523 17.2095L2.37629 12.4581C2.41845 12.3317 2.40836 12.1936 2.34825 12.0746C1.78869 10.9668 1.49872 9.74245 1.50195 8.50133L1.50195 8.50022C1.50253 7.01482 1.91665 5.55891 2.69792 4.29556C3.4792 3.03222 4.59678 2.01134 5.92548 1.34728L5.92548 1.34728L5.92738 1.34633C7.0352 0.786764 8.25953 0.496791 9.50065 0.500028H9.50195H9.98796C11.9444 0.611298 13.7917 1.43858 15.1775 2.82444C16.5634 4.21031 17.3907 6.05759 17.502 8.01402L17.502 8.50003Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 925 B |
|
After Width: | Height: | Size: 62 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="22" viewBox="0 0 18 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.002 1H3.00195C2.47152 1 1.96281 1.21071 1.58774 1.58579C1.21267 1.96086 1.00195 2.46957 1.00195 3V19C1.00195 19.5304 1.21267 20.0391 1.58774 20.4142C1.96281 20.7893 2.47152 21 3.00195 21H15.002C15.5324 21 16.0411 20.7893 16.4162 20.4142C16.7912 20.0391 17.002 19.5304 17.002 19V8L10.002 1Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.002 1V8H17.002" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 568 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="22" viewBox="0 0 18 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.002 1H3.00195C2.47152 1 1.96281 1.21071 1.58774 1.58579C1.21267 1.96086 1.00195 2.46957 1.00195 3V19C1.00195 19.5304 1.21267 20.0391 1.58774 20.4142C1.96281 20.7893 2.47152 21 3.00195 21H15.002C15.5324 21 16.0411 20.7893 16.4162 20.4142C16.7912 20.0391 17.002 19.5304 17.002 19V8L10.002 1Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.002 1V8H17.002" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 568 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.002 19C14.9725 19 19.002 14.9706 19.002 10C19.002 5.02944 14.9725 1 10.002 1C5.03139 1 1.00195 5.02944 1.00195 10C1.00195 14.9706 5.03139 19 10.002 19Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.38281 7.3C7.59441 6.6985 8.01205 6.1913 8.56177 5.86822C9.11149 5.54514 9.75782 5.42704 10.3863 5.53484C11.0147 5.64264 11.5847 5.96937 11.9954 6.45718C12.406 6.94498 12.6308 7.56237 12.6298 8.2C12.6298 10 9.92981 10.9 9.92981 10.9" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.002 14.5H10.011" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 742 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.002 19C14.9725 19 19.002 14.9706 19.002 10C19.002 5.02944 14.9725 1 10.002 1C5.03139 1 1.00195 5.02944 1.00195 10C1.00195 14.9706 5.03139 19 10.002 19Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.38281 7.3C7.59441 6.6985 8.01205 6.1913 8.56177 5.86822C9.11149 5.54514 9.75782 5.42704 10.3863 5.53484C11.0147 5.64264 11.5847 5.96937 11.9954 6.45718C12.406 6.94498 12.6308 7.56237 12.6298 8.2C12.6298 10 9.92981 10.9 9.92981 10.9" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.002 14.5H10.011" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 742 B |
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="56" height="56" rx="4" fill="#2F2F2F"/>
|
||||||
|
<g clip-path="url(#clip0_3970_2549)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 12C19.16 12 12 19.16 12 28C12 35.08 16.58 41.06 22.94 43.18C23.74 43.32 24.04 42.84 24.04 42.42C24.04 42.04 24.02 40.78 24.02 39.44C20 40.18 18.96 38.46 18.64 37.56C18.46 37.1 17.68 35.68 17 35.3C16.44 35 15.64 34.26 16.98 34.24C18.24 34.22 19.14 35.4 19.44 35.88C20.88 38.3 23.18 37.62 24.1 37.2C24.24 36.16 24.66 35.46 25.12 35.06C21.56 34.66 17.84 33.28 17.84 27.16C17.84 25.42 18.46 23.98 19.48 22.86C19.32 22.46 18.76 20.82 19.64 18.62C19.64 18.62 20.98 18.2 24.04 20.26C25.32 19.9 26.68 19.72 28.04 19.72C29.4 19.72 30.76 19.9 32.04 20.26C35.1 18.18 36.44 18.62 36.44 18.62C37.32 20.82 36.76 22.46 36.6 22.86C37.62 23.98 38.24 25.4 38.24 27.16C38.24 33.3 34.5 34.66 30.94 35.06C31.52 35.56 32.02 36.52 32.02 38.02C32.02 40.16 32 41.88 32 42.42C32 42.84 32.3 43.34 33.1 43.18C39.42 41.06 44 35.06 44 28C44 19.16 36.84 12 28 12Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_3970_2549">
|
||||||
|
<rect width="32" height="32" fill="white" transform="translate(12 12)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 188 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0L-1.48522e-08 13.3913L4.40052 13.3913L4.40052 4.46465L22 4.46465L22 2.44001e-08L0 0Z" fill="#FF8444"/>
|
||||||
|
<path d="M17.5995 8.60864L17.5995 17.5353L-9.90052e-09 17.5353L-1.48522e-08 22L22 22L22 8.60864L17.5995 8.60864Z" fill="#FF8444"/>
|
||||||
|
<path d="M13.3915 8.60864L8.60889 8.60864L8.60889 13.3913L13.3915 13.3913L13.3915 8.60864Z" fill="#FF8444"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 459 B |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.22417 1H1.00195V7.22222H7.22417V1Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17.0015 1H10.7793V7.22222H17.0015V1Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17.0015 10.7778H10.7793V17H17.0015V10.7778Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.22417 10.7778H1.00195V17H7.22417V10.7778Z" stroke="#9E9E9E" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 573 B |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.22417 1H1.00195V7.22222H7.22417V1Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17.0015 1H10.7793V7.22222H17.0015V1Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17.0015 10.7778H10.7793V17H17.0015V10.7778Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.22417 10.7778H1.00195V17H7.22417V10.7778Z" stroke="#FF8544" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 61 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_4467_7657)">
|
||||||
|
<path d="M6.54065 20.7133C6.54065 18.9072 5.07648 17.443 3.27033 17.443C1.46417 17.443 0 18.9072 0 20.7133C0 22.5195 1.46417 23.9837 3.27033 23.9837C5.07648 23.9837 6.54065 22.5195 6.54065 20.7133Z" fill="#17BCAF"/>
|
||||||
|
<path d="M23.9838 16.3516C23.9838 16.7226 23.958 17.0851 23.9062 17.441C23.3841 21.0997 20.2648 23.9213 16.4767 23.9817C16.4358 23.9817 16.3948 23.9817 16.3538 23.9817H11.994C10.1884 23.9817 8.72378 22.5169 8.72378 20.7113C8.72378 19.8075 9.09048 18.9921 9.68154 18.3988C10.2748 17.8056 11.0902 17.441 11.994 17.441H16.3171C16.8974 17.441 17.4043 17.0031 17.4432 16.4228C17.4841 15.808 17.0118 15.2924 16.4121 15.2622C16.3948 15.2622 16.3754 15.2622 16.3559 15.2622H7.63439C3.78805 15.2622 0.606175 12.419 0.0798164 8.72161C0.0258865 8.36564 0 8.00109 0 7.63222C0 7.26331 0.0258865 6.89875 0.0776594 6.5428C0.60186 2.88203 3.72118 0.062559 7.50708 0C7.54807 0 7.58907 0 7.63006 0H11.9897C13.7975 0 15.2622 1.46475 15.2622 3.27033C15.2622 4.1742 14.8955 4.98961 14.3044 5.58285C13.7112 6.17608 12.8958 6.54065 11.9919 6.54065H7.66889C7.08858 6.54065 6.58163 6.97856 6.5428 7.55888C6.50182 8.17364 6.97424 8.68919 7.57394 8.71945C7.59123 8.71945 7.61061 8.71945 7.63006 8.71945H16.3516C20.1958 8.71945 23.3755 11.5626 23.904 15.26C23.9558 15.616 23.9817 15.9806 23.9817 16.3494L23.9838 16.3516Z" fill="#18FFCD"/>
|
||||||
|
<path d="M23.984 3.27033C23.984 1.46417 22.5199 0 20.7137 0C18.9076 0 17.4434 1.46417 17.4434 3.27033C17.4434 5.07648 18.9076 6.54065 20.7137 6.54065C22.5199 6.54065 23.984 5.07648 23.984 3.27033Z" fill="#17BCAF"/>
|
||||||
|
<path d="M20.6855 19.622C20.6855 21.9884 18.8002 23.917 16.4488 23.9817C16.4078 23.9817 16.3669 23.9817 16.3259 23.9817H11.9661C10.1605 23.9817 8.6958 22.517 8.6958 20.7114C8.6958 19.8075 9.06251 18.9921 9.65357 18.3989C10.2469 17.8057 11.0623 17.441 11.9661 17.441H16.2892C16.8694 17.441 17.3764 17.0031 17.4153 16.4229C17.4562 15.8081 16.9838 15.2925 16.3841 15.2623C18.7657 15.2904 20.6898 17.2318 20.6898 19.622H20.6855Z" fill="url(#paint0_linear_4467_7657)"/>
|
||||||
|
<path d="M3.27237 4.35971C3.27237 1.99326 5.15778 0.0668734 7.50916 0C7.55015 0 7.59107 0 7.63206 0H11.9918C13.7974 0 15.2621 1.46475 15.2621 3.27032C15.2621 4.1742 14.8954 4.98961 14.3044 5.58285C13.7111 6.17608 12.8957 6.54065 11.9918 6.54065H7.66874C7.08847 6.54065 6.58154 6.97856 6.5427 7.55888C6.50172 8.17364 6.97414 8.68919 7.57385 8.71945C5.19229 8.69135 3.26807 6.7499 3.26807 4.35971H3.27237Z" fill="url(#paint1_linear_4467_7657)"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_4467_7657" x1="8.72017" y1="15.2623" x2="20.7103" y2="15.2623" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#18C2B0"/>
|
||||||
|
<stop offset="1" stop-color="#0B5C53"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4467_7657" x1="15.2601" y1="0" x2="3.26995" y2="0" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#18C2B0"/>
|
||||||
|
<stop offset="1" stop-color="#0B5C53"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_4467_7657">
|
||||||
|
<rect width="24" height="24" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,253 @@
|
|||||||
|
const { Builder, By, until } = require('selenium-webdriver');
|
||||||
|
const chrome = require('selenium-webdriver/chrome');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
console.log('Starting Selenium script for testing pages...');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const userDataDir = path.join(__dirname, 'chrome-user-data', `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`);
|
||||||
|
fs.mkdirSync(userDataDir, { recursive: true });
|
||||||
|
|
||||||
|
let options = new chrome.Options();
|
||||||
|
options.addArguments('--no-sandbox');
|
||||||
|
options.addArguments('--headless');
|
||||||
|
|
||||||
|
let driver = await new Builder()
|
||||||
|
.forBrowser('chrome')
|
||||||
|
.setChromeOptions(options)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
const SuccessfullyLoadedPath = [];
|
||||||
|
const FailedToLoadPath = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await driver.manage().window().setRect({ width: 1600, height: 1200 });
|
||||||
|
await driver.manage().window().maximize()
|
||||||
|
await driver.manage().setTimeouts({ implicit: 15000 });
|
||||||
|
|
||||||
|
const frontendURL = process.argv[2];
|
||||||
|
const routes = process.argv.slice(3);
|
||||||
|
|
||||||
|
console.log('Frontend URL:', frontendURL);
|
||||||
|
const isCloud = frontendURL === 'http://localhost:3002' || frontendURL === 'https://sandbox.shuffler.io' || frontendURL === 'https://shuffler.io';
|
||||||
|
|
||||||
|
if (isCloud) {
|
||||||
|
// Login Credentials
|
||||||
|
const LOGIN_URL = `${frontendURL}/login`;
|
||||||
|
// put your login credentials here
|
||||||
|
const USERNAME = '';
|
||||||
|
const PASSWORD = '';
|
||||||
|
|
||||||
|
console.log('Logging in...');
|
||||||
|
await driver.get(LOGIN_URL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await driver.wait(until.elementLocated(By.css('#emailfield')), 10000);
|
||||||
|
await driver.findElement(By.css('#emailfield')).sendKeys(USERNAME);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#outlined-password-input')), 10000);
|
||||||
|
await driver.findElement(By.css('#outlined-password-input')).sendKeys(PASSWORD);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#loginButton')), 10000);
|
||||||
|
await driver.findElement(By.css('#loginButton')).click();
|
||||||
|
|
||||||
|
// Ensure login success by checking URL change
|
||||||
|
await driver.wait(async () => {
|
||||||
|
const url = await driver.getCurrentUrl();
|
||||||
|
return url.includes('welcome');
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
console.log('Successfully logged in!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login failed:', error.message);
|
||||||
|
FailedToLoadPath.push(LOGIN_URL);
|
||||||
|
await driver.quit();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
// Steps for onprem testing
|
||||||
|
// 1. Login
|
||||||
|
// 2. Create new workflow
|
||||||
|
|
||||||
|
// Write your own login credentials here if you are testing onprem locally
|
||||||
|
const USERNAME = 'demo@demo.io';
|
||||||
|
const PASSWORD = 'supercoolpassword';
|
||||||
|
const WORKFLOW_URL = `${frontendURL}/workflows`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Login
|
||||||
|
console.log('Logging in...');
|
||||||
|
await driver.get(`${frontendURL}/login`);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#emailfield')), 10000);
|
||||||
|
await driver.findElement(By.css('#emailfield')).sendKeys(USERNAME);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#outlined-password-input')), 10000);
|
||||||
|
await driver.findElement(By.css('#outlined-password-input')).sendKeys(PASSWORD);
|
||||||
|
|
||||||
|
const loginButton = await driver.findElement(By.css('#loginButton'));
|
||||||
|
await driver.executeScript("arguments[0].scrollIntoView(true);", loginButton);
|
||||||
|
await loginButton.click();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Ensure signup success by checking URL change
|
||||||
|
await driver.wait(async () => {
|
||||||
|
const url = await driver.getCurrentUrl();
|
||||||
|
return url.includes('welcome') || url.includes('workflows');
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
|
||||||
|
const isParentPresent = await driver.wait(async () => {
|
||||||
|
return await driver.executeScript(
|
||||||
|
"return document.querySelector('.parent-component') !== null;"
|
||||||
|
);
|
||||||
|
}, 5000).catch(() => false);
|
||||||
|
|
||||||
|
if (!isParentPresent) {
|
||||||
|
const logs = await driver.manage().logs().get('browser');
|
||||||
|
const severeErrors = logs.filter(log => log.level.name === 'SEVERE');
|
||||||
|
if (severeErrors.length > 0) {
|
||||||
|
const crashCausingErrors = severeErrors.filter(err => {
|
||||||
|
return !err.message.includes('Warning:') &&
|
||||||
|
!err.message.includes('MUI:')
|
||||||
|
});
|
||||||
|
|
||||||
|
console.error(`Page (${frontendURL}/login) did not load correctly:`, crashCausingErrors);
|
||||||
|
FailedToLoadPath.push(`${frontendURL}/login`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Successfully logged in!');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to login:', error.message);
|
||||||
|
FailedToLoadPath.push(WORKFLOW_URL);
|
||||||
|
await driver.quit();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create new workflow
|
||||||
|
console.log('Creating new workflow...');
|
||||||
|
await driver.get(WORKFLOW_URL);
|
||||||
|
|
||||||
|
await driver.sleep(1000);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#create_workflow_button')), 10000);
|
||||||
|
const create_workflow_button = await driver.findElement(By.css('#create_workflow_button'));
|
||||||
|
|
||||||
|
await driver.sleep(1000);
|
||||||
|
await create_workflow_button.click();
|
||||||
|
|
||||||
|
await driver.sleep(1500);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#Enter-Workflow-Name')), 10000);
|
||||||
|
const enter_workflow_name_field = await driver.findElement(By.css('#Enter-Workflow-Name'));
|
||||||
|
|
||||||
|
await driver.sleep(1000);
|
||||||
|
await enter_workflow_name_field.sendKeys("Test Workflow");
|
||||||
|
|
||||||
|
// Wait before saving
|
||||||
|
await driver.sleep(1500);
|
||||||
|
|
||||||
|
await driver.wait(until.elementLocated(By.css('#save_workflow_button')), 10000);
|
||||||
|
const save_workflow_button = await driver.findElement(By.css('#save_workflow_button'));
|
||||||
|
|
||||||
|
await driver.sleep(1000); // Delay before clicking
|
||||||
|
await save_workflow_button.click();
|
||||||
|
|
||||||
|
// Wait for the parent component to appear
|
||||||
|
await driver.sleep(2000);
|
||||||
|
|
||||||
|
const isParentPresent = await driver.wait(async () => {
|
||||||
|
return await driver.executeScript(
|
||||||
|
"return document.querySelector('.parent-component') !== null;"
|
||||||
|
);
|
||||||
|
}, 5000).catch(() => false);
|
||||||
|
|
||||||
|
if (!isParentPresent) {
|
||||||
|
const logs = await driver.manage().logs().get('browser');
|
||||||
|
const severeErrors = logs.filter(log => log.level.name === 'SEVERE');
|
||||||
|
if (severeErrors.length > 0) {
|
||||||
|
const crashCausingErrors = severeErrors.filter(err => {
|
||||||
|
return !err.message.includes('Warning:') &&
|
||||||
|
!err.message.includes('MUI:');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.error(`Page (${WORKFLOW_URL}) did not load correctly:`, crashCausingErrors);
|
||||||
|
FailedToLoadPath.push(`${WORKFLOW_URL}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create new workflow:', error.message);
|
||||||
|
FailedToLoadPath.push(WORKFLOW_URL);
|
||||||
|
await driver.quit();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get routes from command line arguments
|
||||||
|
if (routes.length === 0) {
|
||||||
|
console.error('No routes found to test.');
|
||||||
|
await driver.quit();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`Found ${routes.length} routes to test.`);
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
const url = `${frontendURL}/${route}`;
|
||||||
|
console.log(`Testing route: ${url}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await driver.get(url);
|
||||||
|
await driver.sleep(3000);
|
||||||
|
|
||||||
|
// Wait for document readiness
|
||||||
|
await driver.wait(async () => {
|
||||||
|
return await driver.executeScript('return document.readyState') === 'complete';
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
const isParentPresent = await driver.wait(async () => {
|
||||||
|
return await driver.executeScript(
|
||||||
|
"return document.querySelector('.parent-component') !== null;"
|
||||||
|
);
|
||||||
|
}, 5000).catch(() => false);
|
||||||
|
|
||||||
|
if (!isParentPresent) {
|
||||||
|
const logs = await driver.manage().logs().get('browser');
|
||||||
|
const severeErrors = logs.filter(log => log.level.name === 'SEVERE');
|
||||||
|
if (severeErrors.length > 0) {
|
||||||
|
const crashCausingErrors = severeErrors.filter(err => {
|
||||||
|
return !err.message.includes('Warning:') &&
|
||||||
|
!err.message.includes('MUI:')
|
||||||
|
});
|
||||||
|
|
||||||
|
console.error(`Page (${url}) did not load correctly:`, crashCausingErrors);
|
||||||
|
FailedToLoadPath.push(url);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Successfully loaded: ${url}`);
|
||||||
|
SuccessfullyLoadedPath.push(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to load ${url}:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
console.log("Total pages tested: ", SuccessfullyLoadedPath.length + FailedToLoadPath.length);
|
||||||
|
console.log("Successfully loaded pages: ", SuccessfullyLoadedPath.length);
|
||||||
|
if (FailedToLoadPath.length > 0) {
|
||||||
|
console.log("Failed to load pages: ", FailedToLoadPath.length);
|
||||||
|
console.log("Failed to load pages paths: ", FailedToLoadPath);
|
||||||
|
process.exit(1);
|
||||||
|
}else {
|
||||||
|
console.log("No pages failed to load. Congrats!");
|
||||||
|
}
|
||||||
|
await driver.quit();
|
||||||
|
fs.rmSync(userDataDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
|
|
||||||
import { Link, Route, Routes, BrowserRouter, useNavigate } from "react-router-dom";
|
import { Link, Route, Routes, BrowserRouter, useNavigate } from "react-router-dom";
|
||||||
import { CookiesProvider } from "react-cookie";
|
import { CookiesProvider } from "react-cookie";
|
||||||
@@ -12,12 +12,16 @@ import Header from "./components/NewHeader.jsx";
|
|||||||
import HealthPage from "./components/HealthPage.jsx";
|
import HealthPage from "./components/HealthPage.jsx";
|
||||||
|
|
||||||
//import Header from "./components/Header.jsx";
|
//import Header from "./components/Header.jsx";
|
||||||
import theme from "./theme.jsx";
|
import theme, { getTheme } from "./theme.jsx";
|
||||||
import Apps from "./views/Apps.jsx";
|
import Apps from "./views/Apps.jsx";
|
||||||
import Apps2 from "./views/Apps2.jsx";
|
import Apps2 from "./views/Apps2.jsx";
|
||||||
import AppCreator from "./views/AppCreator.jsx";
|
import AppCreator from "./views/AppCreator.jsx";
|
||||||
import DetectionDashBoard from "./views/DetectionDashboard.jsx";
|
import DetectionDashBoard from "./views/DetectionDashboard.jsx";
|
||||||
|
|
||||||
|
// LLM related tests
|
||||||
|
import ChatBot from "./components/ChatBot.jsx";
|
||||||
|
import AgentUI from "./views/AgentUI.jsx";
|
||||||
|
|
||||||
import Welcome from "./views/Welcome.jsx";
|
import Welcome from "./views/Welcome.jsx";
|
||||||
import Dashboard from "./views/Dashboard.jsx";
|
import Dashboard from "./views/Dashboard.jsx";
|
||||||
import DashboardView from "./views/DashboardViews.jsx";
|
import DashboardView from "./views/DashboardViews.jsx";
|
||||||
@@ -25,6 +29,7 @@ import AdminSetup from "./views/AdminSetup.jsx";
|
|||||||
import Admin from "./views/Admin.jsx";
|
import Admin from "./views/Admin.jsx";
|
||||||
import Docs from "./views/Docs.jsx";
|
import Docs from "./views/Docs.jsx";
|
||||||
import Usecases2 from "./views/Usecases2.jsx";
|
import Usecases2 from "./views/Usecases2.jsx";
|
||||||
|
import DashboardViews from "./views/DashboardViews.jsx";
|
||||||
//import Introduction from "./views/Introduction";
|
//import Introduction from "./views/Introduction";
|
||||||
import SetAuthentication from "./views/SetAuthentication.jsx";
|
import SetAuthentication from "./views/SetAuthentication.jsx";
|
||||||
import SetAuthenticationSSO from "./views/SetAuthenticationSSO.jsx";
|
import SetAuthenticationSSO from "./views/SetAuthenticationSSO.jsx";
|
||||||
@@ -33,9 +38,10 @@ import RunWorkflow from "./views/RunWorkflow.jsx";
|
|||||||
import Admin2 from "./views/Admin2.jsx";
|
import Admin2 from "./views/Admin2.jsx";
|
||||||
|
|
||||||
import LoginPage from "./views/LoginPage.jsx";
|
import LoginPage from "./views/LoginPage.jsx";
|
||||||
|
import LoginPageOld from "./views/LoginPageOld.jsx";
|
||||||
|
|
||||||
import SettingsPage from "./views/SettingsPage.jsx";
|
import SettingsPage from "./views/SettingsPage.jsx";
|
||||||
import KeepAlive from "./views/KeepAlive.jsx";
|
import KeepAlive from "./views/KeepAlive.jsx";
|
||||||
|
|
||||||
import { ThemeProvider } from "@mui/material/styles";
|
import { ThemeProvider } from "@mui/material/styles";
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
|
|
||||||
@@ -57,7 +63,8 @@ import 'react-toastify/dist/ReactToastify.css';
|
|||||||
|
|
||||||
import Drift from "react-driftjs";
|
import Drift from "react-driftjs";
|
||||||
|
|
||||||
import { AppContext } from './context/ContextApi.jsx';
|
import { Context } from './context/ContextApi.jsx';
|
||||||
|
import Navbar from "./components/Navbar.jsx";
|
||||||
import Workflows2 from "./views/Workflows2.jsx";
|
import Workflows2 from "./views/Workflows2.jsx";
|
||||||
import AppExplorer from "./views/AppExplorer.jsx";
|
import AppExplorer from "./views/AppExplorer.jsx";
|
||||||
|
|
||||||
@@ -85,7 +92,10 @@ const App = (message, props) => {
|
|||||||
const [dataset, setDataset] = useState(false)
|
const [dataset, setDataset] = useState(false)
|
||||||
const [isLoaded, setIsLoaded] = useState(false)
|
const [isLoaded, setIsLoaded] = useState(false)
|
||||||
const [curpath, setCurpath] = useState(typeof window === "undefined" || window.location === undefined ? "" : window.location.pathname)
|
const [curpath, setCurpath] = useState(typeof window === "undefined" || window.location === undefined ? "" : window.location.pathname)
|
||||||
|
const { themeMode, handleThemeChange, setBrandColor, brandColor,setThemeMode} = useContext(Context);
|
||||||
|
const currentTheme = getTheme(themeMode, brandColor);
|
||||||
|
const mainColor = currentTheme?.palette?.backgroundColor
|
||||||
|
const [isPreviousThemeLight, setIsPreviousThemeLight] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dataset === false) {
|
if (dataset === false) {
|
||||||
@@ -95,6 +105,29 @@ const App = (message, props) => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isDarkPath = curpath === "/" || curpath === "/pricing" || curpath === "/partners" || curpath === "/faq" || curpath === "/professional-services" || curpath === "/contact" || curpath === "/training";
|
||||||
|
if (curpath && isDarkPath) {
|
||||||
|
if (themeMode === "light") {
|
||||||
|
setIsPreviousThemeLight(true)
|
||||||
|
}
|
||||||
|
handleThemeChange("dark")
|
||||||
|
}else if ( !isDarkPath && isPreviousThemeLight && userdata?.active_org?.branding?.theme === "light") {
|
||||||
|
handleThemeChange("light")
|
||||||
|
setIsPreviousThemeLight(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDarkPath && userdata && userdata?.active_org?.branding?.brand_color !== "#ff8544") {
|
||||||
|
setBrandColor("#ff8544")
|
||||||
|
}else if(!isDarkPath && userdata && userdata?.active_org?.branding?.brand_color !== "#ff8544" && userdata?.active_org?.branding?.brand_color?.length > 0) {
|
||||||
|
const brandColor = localStorage.getItem("brandColor")
|
||||||
|
if (brandColor !== null && brandColor !== undefined && brandColor.length > 0) {
|
||||||
|
setBrandColor(brandColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [themeMode, curpath, userdata])
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isLoaded &&
|
isLoaded &&
|
||||||
!isLoggedIn &&
|
!isLoggedIn &&
|
||||||
@@ -159,7 +192,16 @@ const App = (message, props) => {
|
|||||||
{ path: "/" }
|
{ path: "/" }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
if (responseJson?.theme?.length > 0) {
|
||||||
|
handleThemeChange(responseJson.theme)
|
||||||
|
}else{
|
||||||
|
handleThemeChange("dark")
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
handleThemeChange("dark")
|
||||||
|
setThemeMode("dark")
|
||||||
|
localStorage.removeItem("theme");
|
||||||
|
}
|
||||||
|
|
||||||
// Handling Ethereum update
|
// Handling Ethereum update
|
||||||
|
|
||||||
@@ -182,10 +224,11 @@ const App = (message, props) => {
|
|||||||
const includedData =
|
const includedData =
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.backgroundColor,
|
backgroundColor: mainColor,
|
||||||
color: "rgba(255, 255, 255, 0.65)",
|
color: "rgba(255, 255, 255, 0.65)",
|
||||||
minHeight: "100vh",
|
minHeight: "100vh",
|
||||||
}}
|
}}
|
||||||
|
className='parent-component'
|
||||||
>
|
>
|
||||||
<ScrollToTop
|
<ScrollToTop
|
||||||
getUserNotifications={getUserNotifications}
|
getUserNotifications={getUserNotifications}
|
||||||
@@ -211,7 +254,20 @@ const App = (message, props) => {
|
|||||||
|
|
||||||
{ window?.location?.pathname === "/" || window?.location?.pathname === "/training" || !(isLoggedIn && isLoaded) ? (
|
{ window?.location?.pathname === "/" || window?.location?.pathname === "/training" || !(isLoggedIn && isLoaded) ? (
|
||||||
<div style={{ minHeight: 68, maxHeight: 68 }}>
|
<div style={{ minHeight: 68, maxHeight: 68 }}>
|
||||||
<Header
|
{/* <Header
|
||||||
|
notifications={notifications}
|
||||||
|
setNotifications={setNotifications}
|
||||||
|
userdata={userdata}
|
||||||
|
cookies={cookies}
|
||||||
|
removeCookie={removeCookie}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
setIsLoggedIn={setIsLoggedIn}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
curpath={curpath}
|
||||||
|
{...props}
|
||||||
|
/> */}
|
||||||
|
<Navbar
|
||||||
notifications={notifications}
|
notifications={notifications}
|
||||||
setNotifications={setNotifications}
|
setNotifications={setNotifications}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
@@ -235,6 +291,7 @@ const App = (message, props) => {
|
|||||||
<div style={{ height: 60 }} />
|
<div style={{ height: 60 }} />
|
||||||
*/}
|
*/}
|
||||||
<Routes>
|
<Routes>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/login"
|
path="/login"
|
||||||
@@ -242,7 +299,8 @@ const App = (message, props) => {
|
|||||||
<LoginPage
|
<LoginPage
|
||||||
isLoggedIn={isLoggedIn}
|
isLoggedIn={isLoggedIn}
|
||||||
setIsLoggedIn={setIsLoggedIn}
|
setIsLoggedIn={setIsLoggedIn}
|
||||||
register={true}
|
register={false}
|
||||||
|
inregister={false}
|
||||||
isLoaded={isLoaded}
|
isLoaded={isLoaded}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
setCookie={setCookie}
|
setCookie={setCookie}
|
||||||
@@ -252,6 +310,63 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/login2"
|
||||||
|
element={
|
||||||
|
<LoginPageOld
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
setIsLoggedIn={setIsLoggedIn}
|
||||||
|
register={false}
|
||||||
|
inregister={false}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
setCookie={setCookie}
|
||||||
|
cookies={cookies}
|
||||||
|
checkLogin={checkLogin}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/loginsetup"
|
||||||
|
element={
|
||||||
|
<LoginPageOld
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
setIsLoggedIn={setIsLoggedIn}
|
||||||
|
register={false}
|
||||||
|
inregister={false}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
setCookie={setCookie}
|
||||||
|
cookies={cookies}
|
||||||
|
checkLogin={checkLogin}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/register"
|
||||||
|
element={
|
||||||
|
<LoginPage
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
setIsLoggedIn={setIsLoggedIn}
|
||||||
|
inregister={true}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
setCookie={setCookie}
|
||||||
|
cookies={cookies}
|
||||||
|
checkLogin={checkLogin}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/admin2"
|
path="/admin2"
|
||||||
@@ -289,13 +404,14 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route exact path="/search" element={<Search serverside={false} isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor} {...props} /> } />
|
<Route exact path="/search" element={<Search serverside={false} isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor} {...props} /> } />
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/admin/:key"
|
path="/admin/:key"
|
||||||
element={
|
element={
|
||||||
<Admin
|
<Admin
|
||||||
isLoggedIn={isLoggedIn}
|
isLoggedIn={isLoggedIn}
|
||||||
|
userdata={userdata}
|
||||||
setIsLoggedIn={setIsLoggedIn}
|
setIsLoggedIn={setIsLoggedIn}
|
||||||
register={true}
|
register={true}
|
||||||
isLoaded={isLoaded}
|
isLoaded={isLoaded}
|
||||||
@@ -353,9 +469,10 @@ const App = (message, props) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/AdminSetup"
|
path="/adminsetup"
|
||||||
element={
|
element={
|
||||||
<AdminSetup
|
<AdminSetup
|
||||||
isLoaded={isLoaded}
|
isLoaded={isLoaded}
|
||||||
@@ -365,6 +482,7 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/detectionframework"
|
path="/detectionframework"
|
||||||
@@ -458,8 +576,8 @@ const App = (message, props) => {
|
|||||||
checkLogin={checkLogin}
|
checkLogin={checkLogin}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
surfaceColor={theme.palette.surfaceColor}
|
surfaceColor={currentTheme.palette.surfaceColor}
|
||||||
inputColor={theme.palette.inputColor}
|
inputColor={currentTheme.palette.inputColor}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@@ -476,8 +594,8 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route exact path="/apps/:appid" element={<AppExplorer userdata={userdata} isLoggedIn={isLoggedIn} isLoaded={isLoaded} globalUrl={globalUrl} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor} checkLogin={checkLogin} {...props} />} />
|
<Route exact path="/apps/:appid" element={<AppExplorer userdata={userdata} isLoggedIn={isLoggedIn} isLoaded={isLoaded} globalUrl={globalUrl} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor} checkLogin={checkLogin} {...props} />} />
|
||||||
<Route exact path="/apis/:appid" element={<ApiExplorerWrapper serverside={false} userdata={userdata} isLoggedIn={isLoggedIn} isMobile={false} selectedApp={undefined} isLoaded={isLoaded}globalUrl={globalUrl} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor} checkLogin={checkLogin} {...props} />} />
|
<Route exact path="/apis/:appid" element={<ApiExplorerWrapper serverside={false} userdata={userdata} isLoggedIn={isLoggedIn} isMobile={false} selectedApp={undefined} isLoaded={isLoaded}globalUrl={globalUrl} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor} checkLogin={checkLogin} {...props} />} />
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/detections/sigma"
|
path="/detections/sigma"
|
||||||
@@ -549,14 +667,40 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route exact path="/workflows/:key/code" element={<CodeWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor}{...props} />} />
|
<Route exact path="/workflows/:key/code" element={<CodeWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor}{...props} />} />
|
||||||
<Route exact path="/workflows/:key/run" element={<RunWorkflow userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor}{...props} /> } />
|
<Route exact path="/workflows/:key/run" element={<RunWorkflow userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor}{...props} /> } />
|
||||||
<Route exact path="/workflows/:key/execute" element={<RunWorkflow userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor}{...props} /> } />
|
<Route exact path="/workflows/:key/execute" element={<RunWorkflow userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor}{...props} /> } />
|
||||||
|
|
||||||
<Route exact path="/forms" element={<RunWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor}{...props} />} />
|
<Route exact path="/forms" element={<RunWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor}{...props} />} />
|
||||||
<Route exact path="/forms/:key/run" element={<RunWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor}{...props} />} />
|
<Route exact path="/forms/:key/run" element={<RunWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor}{...props} />} />
|
||||||
<Route exact path="/forms/:key" element={<RunWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={theme.palette.surfaceColor} inputColor={theme.palette.inputColor}{...props} />} />
|
<Route exact path="/forms/:key" element={<RunWorkflow serverside={false} userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} surfaceColor={currentTheme.palette.surfaceColor} inputColor={currentTheme.palette.inputColor}{...props} />} />
|
||||||
|
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/legal/:key"
|
||||||
|
element={
|
||||||
|
<Docs
|
||||||
|
isMobile={isMobile}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/legal"
|
||||||
|
element={
|
||||||
|
<Docs
|
||||||
|
isMobile={isMobile}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/docs/:key"
|
path="/docs/:key"
|
||||||
@@ -574,7 +718,6 @@ const App = (message, props) => {
|
|||||||
exact
|
exact
|
||||||
path="/docs"
|
path="/docs"
|
||||||
element={
|
element={
|
||||||
//navigate(`/docs/about`)
|
|
||||||
<Docs
|
<Docs
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
isLoaded={isLoaded}
|
isLoaded={isLoaded}
|
||||||
@@ -614,7 +757,7 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route exact path="/login/:key/mfa-setup" element={<MFASetUp setCookie={setCookie} serverside={false} mainColor={theme.palette.backgroundColor} userdata={userdata} stripeKey={undefined} globalUrl={globalUrl} inputColor={theme.palette.inputColor} isLoaded={isLoaded} {...props} />} />
|
<Route exact path="/login/:key/mfa-setup" element={<MFASetUp setCookie={setCookie} serverside={false} mainColor={currentTheme.palette.backgroundColor} userdata={userdata} stripeKey={undefined} globalUrl={globalUrl} inputColor={currentTheme.palette.inputColor} isLoaded={isLoaded} {...props} />} />
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/login_sso"
|
path="/login_sso"
|
||||||
@@ -648,18 +791,92 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/dashboards"
|
path="/dashboard"
|
||||||
element={
|
element={
|
||||||
<DashboardView
|
<DashboardViews
|
||||||
isLoaded={isLoaded}
|
serverside={false}
|
||||||
isLoggedIn={isLoggedIn}
|
isLoaded={isLoaded}
|
||||||
globalUrl={globalUrl}
|
isLoggedIn={isLoggedIn}
|
||||||
{...props}
|
globalUrl={globalUrl}
|
||||||
/>
|
wut={userdata}
|
||||||
}
|
/>
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/dashboards"
|
||||||
|
element={
|
||||||
|
<DashboardViews
|
||||||
|
serverside={false}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
wut={userdata}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/dashboard/:key"
|
||||||
|
element={
|
||||||
|
<DashboardViews
|
||||||
|
serverside={false}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
wut={userdata}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/chat"
|
||||||
|
element={
|
||||||
|
<ChatBot
|
||||||
|
serverside={false}
|
||||||
|
cookies={cookies}
|
||||||
|
removeCookie={removeCookie}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
cookies={cookies}
|
||||||
|
userdata={userdata}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/conversation"
|
||||||
|
element={
|
||||||
|
<ChatBot
|
||||||
|
serverside={false}
|
||||||
|
cookies={cookies}
|
||||||
|
removeCookie={removeCookie}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
cookies={cookies}
|
||||||
|
userdata={userdata}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/dashboards/:key"
|
||||||
|
element={
|
||||||
|
<DashboardViews
|
||||||
|
serverside={false}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
wut={userdata}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/welcome"
|
path="/welcome"
|
||||||
@@ -677,6 +894,22 @@ const App = (message, props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/agents"
|
||||||
|
element={
|
||||||
|
<AgentUI
|
||||||
|
serverside={false}
|
||||||
|
isLoaded={isLoaded}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
userdata={userdata}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/"
|
path="/"
|
||||||
@@ -705,8 +938,7 @@ const App = (message, props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext>
|
<ThemeProvider theme={currentTheme} defaultMode="dark">
|
||||||
<ThemeProvider theme={theme}>
|
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<CookiesProvider>
|
<CookiesProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
@@ -722,11 +954,10 @@ const App = (message, props) => {
|
|||||||
pauseOnFocusLoss
|
pauseOnFocusLoss
|
||||||
draggable
|
draggable
|
||||||
pauseOnHover
|
pauseOnHover
|
||||||
theme="dark"
|
theme={themeMode}
|
||||||
/>
|
/>
|
||||||
</CookiesProvider>
|
</CookiesProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</AppContext>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, useContext, memo } from 'react';
|
import React, { useState, useEffect, useContext, memo } from 'react';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
import OrganizationTab from '../components/OrganizationTab.jsx';
|
import OrganizationTab from '../components/OrganizationTab.jsx';
|
||||||
|
import PartnerTab from '../components/PartnerTab.jsx';
|
||||||
import UserManagmentTab from '../components/UserManagmentTab.jsx';
|
import UserManagmentTab from '../components/UserManagmentTab.jsx';
|
||||||
import CacheView from "../components/CacheView.jsx";
|
import CacheView from "../components/CacheView.jsx";
|
||||||
import Files from "../components/Files.jsx";
|
import Files from "../components/Files.jsx";
|
||||||
@@ -19,24 +20,124 @@ import {
|
|||||||
FmdGoodOutlined as FmdGoodOutlinedIcon,
|
FmdGoodOutlined as FmdGoodOutlinedIcon,
|
||||||
GroupOutlined as GroupOutlinedIcon
|
GroupOutlined as GroupOutlinedIcon
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import theme from '../theme.jsx';
|
import theme, { getTheme } from '../theme.jsx';
|
||||||
import { Button, Tooltip } from '@mui/material';
|
import { Button, Skeleton, Tooltip } from '@mui/material';
|
||||||
import { Index } from 'react-instantsearch-dom';
|
import { Index } from 'react-instantsearch-dom';
|
||||||
import { Context } from '../context/ContextApi.jsx';
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
const PartnerIcon = ({ strokeColor, fillColor = 'transparent', width = 22, height = 22 }) => (
|
||||||
|
<svg
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
viewBox="0 0 18 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M14.5327 4.49465C14.0102 4.60513 13.5779 4.90684 13.2905 5.31071L12.382 1L1.7665 3.23791C1.24516 3.34838 0.911462 3.86034 1.02072 4.38181L3.25807 15L7.57601 14.0901C7.16749 13.8026 6.85992 13.3679 6.74948 12.8393C6.51672 11.7334 7.22331 10.6477 8.32892 10.4149C9.43453 10.1821 10.52 10.8889 10.7527 11.9947C10.8643 12.5221 10.7587 13.0448 10.501 13.4724L14.8189 12.5625L13.9104 8.25182C14.3368 8.50484 14.8533 8.60699 15.3759 8.49652C16.4815 8.2637 17.1893 7.17801 16.9553 6.07212C16.7225 4.96623 15.6371 4.25827 14.5315 4.49228L14.5327 4.49465Z"
|
||||||
|
fill={fillColor}
|
||||||
|
stroke={strokeColor}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
const AdminNavBar = (props) => {
|
const AdminNavBar = (props) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { globalUrl, userdata, isCloud, isLoaded,removeCookie, handleStatusChange, selectedStatus, setSelectedStatus, handleEditOrg, serverside, notifications, handleGetOrg, orgId, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } = props;
|
const { globalUrl, userdata, isCloud,isOrgLoaded, isLoaded,removeCookie, handleStatusChange, selectedStatus, setSelectedStatus, handleEditOrg, serverside, notifications, handleGetOrg, orgId, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } = props;
|
||||||
const [selectedItem, setSelectedItem] = useState("Organization");
|
const [selectedItem, setSelectedItem] = useState("Organization");
|
||||||
const [isSelectedFiles, setIsSelectedFiles] = useState(true);
|
const [isSelectedFiles, setIsSelectedFiles] = useState(true);
|
||||||
const [isSelectedDataStore, setIsSelectedDataStore] = useState(true);
|
const [isSelectedDataStore, setIsSelectedDataStore] = useState(true);
|
||||||
|
const [isIntegrationPartner, setIsIntegrationPartner] = useState(false);
|
||||||
|
const [isChildOrg, setIsChildOrg] = useState(false);
|
||||||
|
const [isGlobalUser, setIsGlobalUser] = useState(false);
|
||||||
|
const [visibleItems, setVisibleItems] = useState([]);
|
||||||
|
const [isUserDataLoaded, setIsUserDataLoaded] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userdata && userdata?.active_org?.id?.length > 0) {
|
||||||
|
setIsUserDataLoaded(true);
|
||||||
|
}
|
||||||
|
}, [userdata]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const { themeMode, brandColor } = React.useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
|
const HandlePartnerChange = () => {
|
||||||
|
if (userdata?.id?.length > 0) {
|
||||||
|
const isIntegrationPartner = userdata?.org_status?.includes("integration_partner") || false;
|
||||||
|
setIsIntegrationPartner(isIntegrationPartner);
|
||||||
|
const isChildOrg = userdata?.org_status?.includes("sub_org") || false;
|
||||||
|
setIsChildOrg(isChildOrg);
|
||||||
|
const isGlobalUser = userdata?.active_org?.branding?.global_user || false;
|
||||||
|
setIsGlobalUser(isGlobalUser);
|
||||||
|
} else {
|
||||||
|
setIsIntegrationPartner(false);
|
||||||
|
setIsChildOrg(false);
|
||||||
|
setIsGlobalUser(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userdata && userdata?.id?.length > 0) {
|
||||||
|
HandlePartnerChange();
|
||||||
|
}
|
||||||
|
}, [userdata]);
|
||||||
|
|
||||||
|
const HandleVisibleTabs = () => {
|
||||||
|
if (userdata?.id?.length > 0) {
|
||||||
|
if (userdata?.active_org?.role === "admin" || userdata?.support) {
|
||||||
|
setVisibleItems(items);
|
||||||
|
}else {
|
||||||
|
const filteredItems = items.filter(item => item.text !== "Users" && item.text !== "Files" && item.text !== "Datastore" && item.text !== "Triggers" && item.text !== "Locations");
|
||||||
|
setVisibleItems(filteredItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isIntegrationPartner && isChildOrg && !isGlobalUser) {
|
||||||
|
// Filter out Users and Tenants tabs
|
||||||
|
if (userdata?.active_org?.role === "admin" || userdata?.support) {
|
||||||
|
const filteredItems = items.filter(item =>
|
||||||
|
item.text !== "Users" && item.text !== "Tenants"
|
||||||
|
);
|
||||||
|
setVisibleItems(filteredItems);
|
||||||
|
}else {
|
||||||
|
const filteredItems = items.filter(item =>
|
||||||
|
item.text !== "Users" && item.text !== "Tenants" && item.text !== "Files" && item.text !== "Datastore" && item.text !== "Triggers" && item.text !== "Locations"
|
||||||
|
);
|
||||||
|
setVisibleItems(filteredItems);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HandleVisibleTabs();
|
||||||
|
}
|
||||||
|
}, [isIntegrationPartner, isChildOrg, isGlobalUser, selectedOrganization, userdata]);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
//const leadinfo = selectedOrganization.lead_info === undefined || selectedOrganization.lead_info === null || selectedOrganization.lead_info === "" ? "" : JSON.stringify(selectedOrganization.lead_info)
|
||||||
|
//const isPartner = leadinfo.includes("partner")
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
const tabName = queryParams.get('tab');
|
const tabName = queryParams.get('tab');
|
||||||
|
const partnerTab = queryParams.get('partner_tab');
|
||||||
|
|
||||||
|
// if(!isCloud){
|
||||||
|
// if(tabName === "partner" || partnerTab !== null) {
|
||||||
|
// setSelectedItem("Organization");
|
||||||
|
// navigate(`?tab=organization`, { replace: true });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (partnerTab) {
|
||||||
|
setSelectedItem("Partner");
|
||||||
|
}
|
||||||
if (tabName === "environments") {
|
if (tabName === "environments") {
|
||||||
setSelectedItem("Locations");
|
setSelectedItem("Locations");
|
||||||
} else if (tabName === "suborgs") {
|
} else if (tabName === "suborgs") {
|
||||||
@@ -45,14 +146,15 @@ const AdminNavBar = (props) => {
|
|||||||
setSelectedItem("Datastore");
|
setSelectedItem("Datastore");
|
||||||
}else if (tabName) {
|
}else if (tabName) {
|
||||||
setSelectedItem(tabName.charAt(0).toUpperCase() + tabName.slice(1));
|
setSelectedItem(tabName.charAt(0).toUpperCase() + tabName.slice(1));
|
||||||
} else {
|
}else if (tabName === "partner") {
|
||||||
setSelectedItem("Organization");
|
setSelectedItem("Partner");
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [location.search]);
|
}, [location.search]);
|
||||||
|
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{ iconSrc: <BusinessIcon />, alt: "Organization Icon", text: "Organization", component: OrganizationTab, props: { globalUrl,removeCookie, selectedStatus, isLoaded, setSelectedStatus, handleStatusChange, handleEditOrg, handleGetOrg, userdata, isCloud, serverside, notifications, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } },
|
{ iconSrc: <BusinessIcon />, alt: "Organization Icon", text: "Organization", component: OrganizationTab, props: { isIntegrationPartner, isChildOrg, isGlobalUser,globalUrl,removeCookie, selectedStatus, isLoaded, setSelectedStatus, handleStatusChange, handleEditOrg, handleGetOrg, userdata, isCloud, serverside, notifications, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } },
|
||||||
|
{ iconSrc: undefined, alt: "Partner Icon", text: "Partner", component: PartnerTab, props: { globalUrl,removeCookie, isLoaded, handleGetOrg, userdata, isCloud, serverside, checkLogin, setSelectedOrganization, selectedOrganization } },
|
||||||
{ iconSrc: <PermIdentityIcon />, alt: "Users Icon", text: "Users", component: UserManagmentTab, props: { globalUrl, userdata, serverside, isCloud, selectedOrganization, setSelectedOrganization, handleEditOrg } },
|
{ iconSrc: <PermIdentityIcon />, alt: "Users Icon", text: "Users", component: UserManagmentTab, props: { globalUrl, userdata, serverside, isCloud, selectedOrganization, setSelectedOrganization, handleEditOrg } },
|
||||||
{ iconSrc: <HttpsOutlinedIcon />, alt: "App Auth Icon", text: "App_auth", component: AppAuthTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
|
{ iconSrc: <HttpsOutlinedIcon />, alt: "App Auth Icon", text: "App_auth", component: AppAuthTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
|
||||||
{ iconSrc: <StorageOutlinedIcon />, alt: "Datastore Icon", text: "Datastore", component: CacheView, props: { globalUrl, userdata, selectedOrganization, serverside, isSelectedDataStore, orgId , isCloud} },
|
{ iconSrc: <StorageOutlinedIcon />, alt: "Datastore Icon", text: "Datastore", component: CacheView, props: { globalUrl, userdata, selectedOrganization, serverside, isSelectedDataStore, orgId , isCloud} },
|
||||||
@@ -60,7 +162,7 @@ const AdminNavBar = (props) => {
|
|||||||
{ iconSrc: <AccessTimeOutlinedIcon />, alt: "Trigger Icon", text: "Triggers", component: SchedulesTab, props: { globalUrl, userdata, isCloud, serverside } },
|
{ iconSrc: <AccessTimeOutlinedIcon />, alt: "Trigger Icon", text: "Triggers", component: SchedulesTab, props: { globalUrl, userdata, isCloud, serverside } },
|
||||||
{ iconSrc: <FmdGoodOutlinedIcon />, alt: "Environments Icon", text: "Locations", component: EnvironmentTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
|
{ iconSrc: <FmdGoodOutlinedIcon />, alt: "Environments Icon", text: "Locations", component: EnvironmentTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
|
||||||
{ iconSrc: <GroupOutlinedIcon />, alt: "Tenants Icon", text: "Tenants", component: TenantsTab, props: {isCloud, globalUrl, userdata, serverside, selectedOrganization, setSelectedOrganization, checkLogin } }
|
{ iconSrc: <GroupOutlinedIcon />, alt: "Tenants Icon", text: "Tenants", component: TenantsTab, props: {isCloud, globalUrl, userdata, serverside, selectedOrganization, setSelectedOrganization, checkLogin } }
|
||||||
];
|
].filter(Boolean);
|
||||||
|
|
||||||
const setConfig = (newValue) => {
|
const setConfig = (newValue) => {
|
||||||
setSelectedItem(newValue);
|
setSelectedItem(newValue);
|
||||||
@@ -73,19 +175,80 @@ const AdminNavBar = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isIntegrationPartner && isChildOrg && !isGlobalUser && isOrgLoaded && isUserDataLoaded) {
|
||||||
|
const queryParams = new URLSearchParams(location.search);
|
||||||
|
const tabName = queryParams?.get('admin_tab')?.toLowerCase();
|
||||||
|
if (tabName === "sso" || tabName === "branding") {
|
||||||
|
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
|
||||||
|
setTimeout(() => {
|
||||||
|
setSelectedItem("Organization");
|
||||||
|
navigate(`?admin_tab=org_config`, { replace: true });
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
const tab = params?.get('tab')?.toLowerCase();
|
||||||
|
if (tab === "users" || tab === "tenants") {
|
||||||
|
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
|
||||||
|
setTimeout(() => {
|
||||||
|
setSelectedItem("Organization");
|
||||||
|
navigate(`?admin_tab=org_config`, { replace: true });
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
, 3000);
|
||||||
|
}
|
||||||
|
} else if (userdata && isOrgLoaded && isUserDataLoaded && userdata?.active_org?.role !== "admin" && !userdata?.support) {
|
||||||
|
const queryParams = new URLSearchParams(location.search);
|
||||||
|
const tabName = queryParams?.get('admin_tab')?.toLowerCase();
|
||||||
|
if (tabName === "sso") {
|
||||||
|
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
|
||||||
|
setTimeout(() => {
|
||||||
|
setSelectedItem("Organization");
|
||||||
|
navigate(`?admin_tab=org_config`, { replace: true });
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
const tab = params?.get('tab')?.toLowerCase();
|
||||||
|
if (tab === "users" || tab === "locations" || tab === "environments" || tab === "files" || tab === "datastore" || tab === "triggers") {
|
||||||
|
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
|
||||||
|
setTimeout(() => {
|
||||||
|
setSelectedItem("Organization");
|
||||||
|
navigate(`?admin_tab=org_config`, { replace: true });
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isIntegrationPartner, isChildOrg, isGlobalUser, location.search, userdata, isOrgLoaded, isUserDataLoaded]);
|
||||||
|
|
||||||
|
|
||||||
const renderComponent = () => {
|
const renderComponent = () => {
|
||||||
const selectedItemData = items.find(item => item.text === selectedItem);
|
const selectedItemData = visibleItems.find(item => item.text === selectedItem);
|
||||||
if (!selectedItemData) {
|
if (!selectedItemData) {
|
||||||
setSelectedItem("Organization");
|
setSelectedItem("Organization");
|
||||||
// If no tab is specified, default to "Organization" tab
|
// If no tab is specified, default to "Organization" tab
|
||||||
return <OrganizationTab globalUrl={globalUrl} removeCookie={removeCookie} selectedStatus={selectedStatus} isLoaded={isLoaded} setSelectedStatus={setSelectedStatus} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} userdata={userdata} isCloud={isCloud} serverside={serverside} notifications={notifications} checkLogin={checkLogin} setNotifications={setNotifications} stripeKey={stripeKey} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization}/>;
|
return <OrganizationTab isIntegrationPartner={isIntegrationPartner} isChildOrg={isChildOrg} isGlobalUser={isGlobalUser} globalUrl={globalUrl} removeCookie={removeCookie} selectedStatus={selectedStatus} isLoaded={isLoaded} setSelectedStatus={setSelectedStatus} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} userdata={userdata} isCloud={isCloud} serverside={serverside} notifications={notifications} checkLogin={checkLogin} setNotifications={setNotifications} stripeKey={stripeKey} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization}/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ComponentToRender = selectedItemData.component;
|
const ComponentToRender = selectedItemData.component;
|
||||||
const componentProps = selectedItemData.props;
|
const componentProps = selectedItemData.props;
|
||||||
|
|
||||||
return <ComponentToRender {...componentProps} />;
|
const updatedProps = {
|
||||||
};
|
...componentProps,
|
||||||
|
notifications: notifications,
|
||||||
|
setNotifications: setNotifications,
|
||||||
|
userdata: userdata,
|
||||||
|
selectedOrganization: selectedOrganization
|
||||||
|
};
|
||||||
|
|
||||||
|
return <ComponentToRender {...updatedProps} />;
|
||||||
|
};
|
||||||
|
|
||||||
const defaultImage = "/images/logos/orange_logo.svg"
|
const defaultImage = "/images/logos/orange_logo.svg"
|
||||||
const imageData =
|
const imageData =
|
||||||
@@ -94,15 +257,16 @@ const AdminNavBar = (props) => {
|
|||||||
: selectedOrganization?.image;
|
: selectedOrganization?.image;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
!isOrgLoaded && !isUserDataLoaded ? <Loader /> :
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<div style={{ flexDirection: 'column', width: 220, }}>
|
<div style={{ flexDirection: 'column', width: 220, }}>
|
||||||
<nav style={{ padding: '25px 25px 3px 25px', height: isCloud ? "calc(100% - 60px)" : "calc(100% - 30px)" , fontSize: '16px', borderTopLeftRadius: 8, borderBottomLeftRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
<nav style={{ padding: '25px 25px 3px 25px', height: isCloud ? "calc(100% - 60px)" : "calc(100% - 30px)" , fontSize: '16px', borderTopLeftRadius: 8, borderBottomLeftRadius: 8, background: theme.palette.platformColor, color: '#9CA3AF' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', }}>
|
<div style={{ display: 'flex', alignItems: 'center', }}>
|
||||||
<img loading="lazy" src={imageData} alt="Logo" style={{ width: '30px', borderRadius: 8, height: '30px', marginRight: '8px' }} />
|
<img loading="lazy" src={imageData} alt="Logo" style={{ width: '30px', borderRadius: 8, height: '30px', marginRight: '8px' }} />
|
||||||
<div style={{
|
<div style={{
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: "#FFFFFF",
|
color: theme.palette.text.primary,
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
@@ -111,8 +275,8 @@ const AdminNavBar = (props) => {
|
|||||||
marginLeft: 5,
|
marginLeft: 5,
|
||||||
}}>{selectedOrganization?.name}</div>
|
}}>{selectedOrganization?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ borderTop: '1px solid #494949', marginTop: 23 }} />
|
<div style={{ borderTop: theme.palette.defaultBorder, marginTop: 23 }} />
|
||||||
{items.map((item, index) => (
|
{visibleItems.map((item, index) => (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
key={index}
|
key={index}
|
||||||
title={
|
title={
|
||||||
@@ -129,11 +293,10 @@ const AdminNavBar = (props) => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
sx={{
|
sx={{
|
||||||
gap: 1,
|
gap: 1,
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: "#323232 !important",
|
|
||||||
},
|
|
||||||
"&.MuiButton-root": {
|
"&.MuiButton-root": {
|
||||||
color: selectedItem === item.text ? "#FFFFFF" : "#9E9E9E",
|
color: selectedItem === item.text
|
||||||
|
? theme.palette.text.primary
|
||||||
|
: theme.palette.text.secondary,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
@@ -146,13 +309,16 @@ const AdminNavBar = (props) => {
|
|||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
borderLeft:
|
borderLeft:
|
||||||
selectedItem === item.text
|
selectedItem === item.text
|
||||||
? "3px solid rgba(255, 132, 68, 1)"
|
? `3px solid ${theme.palette.primary.main}`
|
||||||
: "none",
|
: "none",
|
||||||
borderTopLeftRadius: selectedItem === item.text ? "2.5px" : null,
|
borderTopLeftRadius: selectedItem === item.text ? "2.5px" : null,
|
||||||
borderBottomLeftRadius: selectedItem === item.text ? "2.5px" : null,
|
borderBottomLeftRadius: selectedItem === item.text ? "2.5px" : null,
|
||||||
paddingLeft: selectedItem === item.text ? "15px" : "10px",
|
paddingLeft: selectedItem === item.text ? "15px" : "10px",
|
||||||
fontWeight: selectedItem === item.text ? 200 : "normal",
|
fontWeight: selectedItem === item.text ? 200 : "normal",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"&.Mui-disabled": {
|
"&.Mui-disabled": {
|
||||||
color: "#6F6F6F",
|
color: "#6F6F6F",
|
||||||
@@ -161,7 +327,7 @@ const AdminNavBar = (props) => {
|
|||||||
disabled={
|
disabled={
|
||||||
((item.text === "Users") || (item.text === "Files") || (item.text === "Triggers") || (item.text === "Locations")) && !(userdata?.support || userdata?.active_org?.role === "admin")
|
((item.text === "Users") || (item.text === "Files") || (item.text === "Triggers") || (item.text === "Locations")) && !(userdata?.support || userdata?.active_org?.role === "admin")
|
||||||
}
|
}
|
||||||
startIcon={item.iconSrc}
|
startIcon={item?.iconSrc === undefined ? <PartnerIcon strokeColor={selectedItem === item.text ? theme.palette.text.primary : theme.palette.text.secondary} /> : item?.iconSrc}
|
||||||
onClick={() => setConfig(item.text)}
|
onClick={() => setConfig(item.text)}
|
||||||
>
|
>
|
||||||
{item.text.replace(/_/g, " ")}
|
{item.text.replace(/_/g, " ")}
|
||||||
@@ -173,17 +339,132 @@ const AdminNavBar = (props) => {
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<Wrapper2>{renderComponent()}</Wrapper2>
|
|
||||||
|
<Wrapper2>
|
||||||
|
{renderComponent()}
|
||||||
|
</Wrapper2>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AdminNavBar;
|
export default AdminNavBar;
|
||||||
|
|
||||||
|
const Loader = () => {
|
||||||
|
const dummyItems = Array.from({ length: 6 });
|
||||||
|
const dummyNavItems = Array.from({ length: 6 });
|
||||||
|
const dummyTabItems = ['Org Configuration', 'SSO', 'Notifications', 'Billing & Stats', 'Branding'];
|
||||||
|
const { leftSideBarOpenByClick, windowWidth, themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
minHeight: '100vh',
|
||||||
|
maxWidth: '1200px',
|
||||||
|
fontFamily: 'Arial, sans-serif',
|
||||||
|
paddingLeft: leftSideBarOpenByClick ? windowWidth <= 1300 ? 220 : 200 : 80,
|
||||||
|
transition: "padding-left 0.3s ease",
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<div style={{
|
||||||
|
width: '220px',
|
||||||
|
backgroundColor: theme.palette.platformColor,
|
||||||
|
borderTopLeftRadius: '8px',
|
||||||
|
borderBottomLeftRadius: '8px',
|
||||||
|
padding: '25px 25px 3px 25px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '20px' }}>
|
||||||
|
<Skeleton
|
||||||
|
width="30px"
|
||||||
|
height="30px"
|
||||||
|
sx={{ borderRadius: '8px', marginRight: '8px', }}
|
||||||
|
/>
|
||||||
|
<Skeleton width="120px" height="24px" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Divider */}
|
||||||
|
<Skeleton
|
||||||
|
width="100%"
|
||||||
|
height="1px"
|
||||||
|
sx={{ marginBottom: '15px' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Nav Items */}
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '5px', width: '100%' }}>
|
||||||
|
{dummyNavItems.map((_, index) => (
|
||||||
|
<div key={index} style={{ display: 'flex', alignItems: 'center', padding: '5px 0' }}>
|
||||||
|
<Skeleton
|
||||||
|
width="18px"
|
||||||
|
height="18px"
|
||||||
|
sx={{ marginRight: '10px' }}
|
||||||
|
/>
|
||||||
|
<Skeleton width={`${100 + Math.random() * 40}px`} height="36px" />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: theme.palette.platformColor,
|
||||||
|
borderTopRightRadius: '8px',
|
||||||
|
borderBottomRightRadius: '8px',
|
||||||
|
borderLeft: theme.palette.defaultBorder,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
borderBottom: theme.palette.defaultBorder,
|
||||||
|
padding: '0 16px'
|
||||||
|
}}>
|
||||||
|
{dummyTabItems.map((_, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '28px 0',
|
||||||
|
borderBottom: index === 0 ? '2px solid #FF8444' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton width={`${80 + Math.random() * 30}px`} height="24px" />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 1, padding: '24px' }}>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', margin: '0 auto', alignItems: 'flex-start' }}>
|
||||||
|
<Skeleton variant='square' width="200px" height="200px" sx={{ marginBottom: '20px' }} />
|
||||||
|
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px', width: '100%', marginTop: '50px' }}>
|
||||||
|
{dummyItems.map((_, index) => (
|
||||||
|
<div key={index} style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
|
||||||
|
<Skeleton width={'400px'} height="36px" />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const PaddingWrapper2 = memo(({ children }) => {
|
const PaddingWrapper2 = memo(({ children }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div div style={{marginBottom: 30, width: "75%" , maxWidth: 1200, height: "100%", boxSizing: 'border-box'}}>
|
<div style={{
|
||||||
|
marginBottom: 30,
|
||||||
|
width: "75%" ,
|
||||||
|
maxWidth: 1200,
|
||||||
|
height: "100%",
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,275 +1,278 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
// import React, { useEffect, useState } from 'react';
|
||||||
import Switch from '@mui/material/Switch';
|
// import Switch from '@mui/material/Switch';
|
||||||
import { Typography, Button } from '@mui/material';
|
// import { Typography, Button } from '@mui/material';
|
||||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
// import { useNavigate, Link, useParams } from "react-router-dom";
|
||||||
import { Bar } from 'react-chartjs-2';
|
// import { Bar } from 'react-chartjs-2';
|
||||||
import Grid from '@mui/material/Grid';
|
// import Grid from '@mui/material/Grid';
|
||||||
import SearchIcon from '@mui/icons-material/Search';
|
// import SearchIcon from '@mui/icons-material/Search';
|
||||||
import NewReleasesIcon from '@mui/icons-material/NewReleases';
|
// import NewReleasesIcon from '@mui/icons-material/NewReleases';
|
||||||
import MailOutlineIcon from '@mui/icons-material/MailOutline';
|
// import MailOutlineIcon from '@mui/icons-material/MailOutline';
|
||||||
|
|
||||||
const AnalyticsTab = (props) => {
|
const AnalyticsTab = (props) => {
|
||||||
const { userdata, globalUrl, serverside } = props;
|
const { userdata, globalUrl, serverside } = props;
|
||||||
const [checked, setChecked] = useState(false);
|
|
||||||
const [selectedOption, setSelectedOption] = useState('all');
|
|
||||||
const [expand, setExpand] = useState(false)
|
|
||||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
|
||||||
|
|
||||||
const handleOptionChange = (option) => {
|
console.log("if you need this, work without react-rechartjs-2")
|
||||||
setSelectedOption(option);
|
|
||||||
// You can perform actions based on the selected option, such as filtering data
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (event) => {
|
// const [checked, setChecked] = useState(false);
|
||||||
setChecked(event.target.checked);
|
// const [selectedOption, setSelectedOption] = useState('all');
|
||||||
};
|
// const [expand, setExpand] = useState(false)
|
||||||
|
// const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||||
|
|
||||||
const allData = {
|
// const handleOptionChange = (option) => {
|
||||||
labels: ['Email analysis', 'Email Management', 'EDR to Ticket', 'Ticket Analysis'],
|
// setSelectedOption(option);
|
||||||
datasets: [
|
// // You can perform actions based on the selected option, such as filtering data
|
||||||
{
|
// };
|
||||||
label: 'Revisions',
|
|
||||||
data: [12, 19, 3, 5], // Data for revisions
|
|
||||||
backgroundColor: '#FF8444',
|
|
||||||
borderWidth: 1,
|
|
||||||
// borderRadius: 60,
|
|
||||||
barPercentage: 0.7,
|
|
||||||
categoryPercentage: 0.5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Runs',
|
|
||||||
data: [8, 15, 5, 8], // Data for runs
|
|
||||||
backgroundColor: '#9747FF',
|
|
||||||
borderWidth: 1,
|
|
||||||
// borderRadius: 60,
|
|
||||||
barPercentage: 0.7,
|
|
||||||
categoryPercentage: 0.5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
let data;
|
// const handleChange = (event) => {
|
||||||
if (selectedOption === 'all') {
|
// setChecked(event.target.checked);
|
||||||
data = allData;
|
// };
|
||||||
} else if (selectedOption === 'revisions') {
|
|
||||||
data = {
|
|
||||||
labels: allData.labels,
|
|
||||||
datasets: [allData.datasets[0]] // Show only revisions data
|
|
||||||
};
|
|
||||||
} else if (selectedOption === 'run') {
|
|
||||||
data = {
|
|
||||||
labels: allData.labels,
|
|
||||||
datasets: [allData.datasets[1]] // Show only runs data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options for the chart
|
// const allData = {
|
||||||
const options = {
|
// labels: ['Email analysis', 'Email Management', 'EDR to Ticket', 'Ticket Analysis'],
|
||||||
scales: {
|
// datasets: [
|
||||||
yAxes: [
|
// {
|
||||||
{
|
// label: 'Revisions',
|
||||||
ticks: {
|
// data: [12, 19, 3, 5], // Data for revisions
|
||||||
beginAtZero: true
|
// backgroundColor: '#FF8444',
|
||||||
}
|
// borderWidth: 1,
|
||||||
}
|
// // borderRadius: 60,
|
||||||
]
|
// barPercentage: 0.7,
|
||||||
},
|
// categoryPercentage: 0.5,
|
||||||
};
|
// },
|
||||||
return (
|
// {
|
||||||
<div style={{ width: 1030, marginLeft: 20, marginTop:10, paddingRight: 17, paddingLeft: 17}}>
|
// label: 'Runs',
|
||||||
<div style={{ width: 985, display: 'flex', alignItems: 'start', paddingTop: 16, paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
// data: [8, 15, 5, 8], // Data for runs
|
||||||
<div style={{ marginLeft: 18 }}>Timeline</div>
|
// backgroundColor: '#9747FF',
|
||||||
</div>
|
// borderWidth: 1,
|
||||||
<div style={{ display: "flex", width: "100%", marginTop: 16 }}>
|
// // borderRadius: 60,
|
||||||
<div>
|
// barPercentage: 0.7,
|
||||||
<div style={{ width: 595, alignItems: 'start', paddingTop: 16, paddingBottom: checked ? 28 : 20, marginRight: 20, fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
// categoryPercentage: 0.5
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
// }
|
||||||
<div style={{ marginLeft: 18, marginRight: 310 }}>Apps</div>
|
// ]
|
||||||
<Switch checked={checked}
|
// };
|
||||||
onChange={handleChange} /> Category
|
|
||||||
<div style={{ marginLeft: 16, borderLeft: "1px solid #D9D9D9", width: 10, height: 15 }} />
|
// let data;
|
||||||
<Link onClick={() => { setExpand(prevExpand => !prevExpand); }} style={{ color: "#FF8444" }}>Expand</Link>
|
// if (selectedOption === 'all') {
|
||||||
</div>
|
// data = allData;
|
||||||
{expand ? null :
|
// } else if (selectedOption === 'revisions') {
|
||||||
<div style={{ marginTop: 8, display: "flex" }}>
|
// data = {
|
||||||
<div style={{ marginLeft: 19, }}>
|
// labels: allData.labels,
|
||||||
<Typography style={{ fontSize: 13, color: "#9E9E9E", textAlign: "start" }}>Onboarding</Typography>
|
// datasets: [allData.datasets[0]] // Show only revisions data
|
||||||
<Grid container spacing={2} style={{ marginTop: 1 }} >
|
// };
|
||||||
<Grid item xs={4}>
|
// } else if (selectedOption === 'run') {
|
||||||
<div style={{ position: 'relative' }}>
|
// data = {
|
||||||
<img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
// labels: allData.labels,
|
||||||
{checked ?
|
// datasets: [allData.datasets[1]] // Show only runs data
|
||||||
<div style={{
|
// };
|
||||||
position: 'absolute',
|
// }
|
||||||
bottom: 0,
|
|
||||||
left: '50%',
|
// // Options for the chart
|
||||||
top: 30,
|
// const options = {
|
||||||
transform: 'translateX(-50%)',
|
// scales: {
|
||||||
backgroundColor: '#2f2f2f',
|
// yAxes: [
|
||||||
borderRadius: '50%',
|
// {
|
||||||
height: 24,
|
// ticks: {
|
||||||
width: 24,
|
// beginAtZero: true
|
||||||
transition: 'transform 0.5s ease',
|
// }
|
||||||
}}><SearchIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
// }
|
||||||
null
|
// ]
|
||||||
}
|
// },
|
||||||
</div>
|
// };
|
||||||
</Grid>
|
// return (
|
||||||
<Grid item xs={4}>
|
// <div style={{ width: 1030, marginLeft: 20, marginTop:10, paddingRight: 17, paddingLeft: 17}}>
|
||||||
<div style={{ position: 'relative' }}>
|
// <div style={{ width: 985, display: 'flex', alignItems: 'start', paddingTop: 16, paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
||||||
<img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
// <div style={{ marginLeft: 18 }}>Timeline</div>
|
||||||
{checked ?
|
// </div>
|
||||||
<div style={{
|
// <div style={{ display: "flex", width: "100%", marginTop: 16 }}>
|
||||||
position: 'absolute',
|
// <div>
|
||||||
bottom: 0,
|
// <div style={{ width: 595, alignItems: 'start', paddingTop: 16, paddingBottom: checked ? 28 : 20, marginRight: 20, fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
||||||
left: '50%',
|
// <div style={{ display: "flex", alignItems: "center" }}>
|
||||||
top: 30,
|
// <div style={{ marginLeft: 18, marginRight: 310 }}>Apps</div>
|
||||||
transform: 'translateX(-50%)',
|
// <Switch checked={checked}
|
||||||
backgroundColor: '#2f2f2f',
|
// onChange={handleChange} /> Category
|
||||||
borderRadius: '50%',
|
// <div style={{ marginLeft: 16, borderLeft: "1px solid #D9D9D9", width: 10, height: 15 }} />
|
||||||
height: 24,
|
// <Link onClick={() => { setExpand(prevExpand => !prevExpand); }} style={{ color: "#FF8444" }}>Expand</Link>
|
||||||
width: 24,
|
// </div>
|
||||||
transition: 'transform 0.5s ease',
|
// {expand ? null :
|
||||||
}}><MailOutlineIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
// <div style={{ marginTop: 8, display: "flex" }}>
|
||||||
null
|
// <div style={{ marginLeft: 19, }}>
|
||||||
}
|
// <Typography style={{ fontSize: 13, color: "#9E9E9E", textAlign: "start" }}>Onboarding</Typography>
|
||||||
</div>
|
// <Grid container spacing={2} style={{ marginTop: 1 }} >
|
||||||
</Grid>
|
// <Grid item xs={4}>
|
||||||
<Grid item xs={4}>
|
// <div style={{ position: 'relative' }}>
|
||||||
<div style={{ position: 'relative' }}>
|
// <img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
||||||
<img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
// {checked ?
|
||||||
{checked ?
|
// <div style={{
|
||||||
<div style={{
|
// position: 'absolute',
|
||||||
position: 'absolute',
|
// bottom: 0,
|
||||||
bottom: 0,
|
// left: '50%',
|
||||||
left: '50%',
|
// top: 30,
|
||||||
top: 30,
|
// transform: 'translateX(-50%)',
|
||||||
transform: 'translateX(-50%)',
|
// backgroundColor: '#2f2f2f',
|
||||||
backgroundColor: '#2f2f2f',
|
// borderRadius: '50%',
|
||||||
borderRadius: '50%',
|
// height: 24,
|
||||||
height: 24,
|
// width: 24,
|
||||||
width: 24,
|
// transition: 'transform 0.5s ease',
|
||||||
transition: 'transform 0.5s ease',
|
// }}><SearchIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
||||||
}}><NewReleasesIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
// null
|
||||||
null
|
// }
|
||||||
}
|
// </div>
|
||||||
</div>
|
// </Grid>
|
||||||
</Grid>
|
// <Grid item xs={4}>
|
||||||
</Grid>
|
// <div style={{ position: 'relative' }}>
|
||||||
</div>
|
// <img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
||||||
<div style={{ borderLeft: "1px solid #494949", justifyContent: "center", alignItems: "center", marginTop: 40, marginLeft: 20, marginRight: 20, height: 40 }}></div>
|
// {checked ?
|
||||||
<div style={{}}>
|
// <div style={{
|
||||||
<Typography style={{ fontSize: 13, color: "#9E9E9E", textAlign: "start" }}>Other</Typography>
|
// position: 'absolute',
|
||||||
<Grid container spacing={2} style={{ marginTop: 1 }} >
|
// bottom: 0,
|
||||||
<Grid item xs={4}>
|
// left: '50%',
|
||||||
<div style={{ position: 'relative' }}>
|
// top: 30,
|
||||||
<img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
// transform: 'translateX(-50%)',
|
||||||
{checked ?
|
// backgroundColor: '#2f2f2f',
|
||||||
<div style={{
|
// borderRadius: '50%',
|
||||||
position: 'absolute',
|
// height: 24,
|
||||||
bottom: 0,
|
// width: 24,
|
||||||
left: '50%',
|
// transition: 'transform 0.5s ease',
|
||||||
top: 30,
|
// }}><MailOutlineIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
||||||
transform: 'translateX(-50%)',
|
// null
|
||||||
backgroundColor: '#2f2f2f',
|
// }
|
||||||
borderRadius: '50%',
|
// </div>
|
||||||
height: 24,
|
// </Grid>
|
||||||
width: 24,
|
// <Grid item xs={4}>
|
||||||
transition: 'transform 0.5s ease',
|
// <div style={{ position: 'relative' }}>
|
||||||
}}><SearchIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
// <img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
||||||
null
|
// {checked ?
|
||||||
}
|
// <div style={{
|
||||||
</div>
|
// position: 'absolute',
|
||||||
</Grid>
|
// bottom: 0,
|
||||||
<Grid item xs={4}>
|
// left: '50%',
|
||||||
<div style={{ position: 'relative' }}>
|
// top: 30,
|
||||||
<img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
// transform: 'translateX(-50%)',
|
||||||
{checked ?
|
// backgroundColor: '#2f2f2f',
|
||||||
<div style={{
|
// borderRadius: '50%',
|
||||||
position: 'absolute',
|
// height: 24,
|
||||||
bottom: 0,
|
// width: 24,
|
||||||
left: '50%',
|
// transition: 'transform 0.5s ease',
|
||||||
top: 30,
|
// }}><NewReleasesIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
||||||
transform: 'translateX(-50%)',
|
// null
|
||||||
backgroundColor: '#2f2f2f',
|
// }
|
||||||
borderRadius: '50%',
|
// </div>
|
||||||
height: 24,
|
// </Grid>
|
||||||
width: 24,
|
// </Grid>
|
||||||
transition: 'transform 10s ease-in-out',
|
// </div>
|
||||||
}}><NewReleasesIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
// <div style={{ borderLeft: "1px solid #494949", justifyContent: "center", alignItems: "center", marginTop: 40, marginLeft: 20, marginRight: 20, height: 40 }}></div>
|
||||||
null
|
// <div style={{}}>
|
||||||
}
|
// <Typography style={{ fontSize: 13, color: "#9E9E9E", textAlign: "start" }}>Other</Typography>
|
||||||
</div>
|
// <Grid container spacing={2} style={{ marginTop: 1 }} >
|
||||||
</Grid>
|
// <Grid item xs={4}>
|
||||||
<Grid item xs={4}>
|
// <div style={{ position: 'relative' }}>
|
||||||
<div style={{ position: 'relative' }}>
|
// <img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
||||||
<img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
// {checked ?
|
||||||
{checked ?
|
// <div style={{
|
||||||
<div style={{
|
// position: 'absolute',
|
||||||
position: 'absolute',
|
// bottom: 0,
|
||||||
bottom: 0,
|
// left: '50%',
|
||||||
left: '50%',
|
// top: 30,
|
||||||
top: 30,
|
// transform: 'translateX(-50%)',
|
||||||
transform: 'translateX(-50%)',
|
// backgroundColor: '#2f2f2f',
|
||||||
backgroundColor: '#2f2f2f',
|
// borderRadius: '50%',
|
||||||
borderRadius: '50%',
|
// height: 24,
|
||||||
height: 24,
|
// width: 24,
|
||||||
width: 24,
|
// transition: 'transform 0.5s ease',
|
||||||
transition: 'transform 10s ease-in-out',
|
// }}><SearchIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
||||||
}}><MailOutlineIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
// null
|
||||||
null
|
// }
|
||||||
}
|
// </div>
|
||||||
</div>
|
// </Grid>
|
||||||
</Grid>
|
// <Grid item xs={4}>
|
||||||
</Grid>
|
// <div style={{ position: 'relative' }}>
|
||||||
</div>
|
// <img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
||||||
</div>}
|
// {checked ?
|
||||||
</div>
|
// <div style={{
|
||||||
<div style={{ width: 595, height: 322, marginTop: 16, paddingTop: 16, paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
// position: 'absolute',
|
||||||
<div style={{ marginLeft: 18, textAlign: "start" }}>Workflows</div>
|
// bottom: 0,
|
||||||
<div style={{textAlign:"center"}}>
|
// left: '50%',
|
||||||
<Button style={{ textTransform: "capitalize", background: selectedOption === 'all' ? "#494949" : "#1A1A1A", borderRadius: selectedOption === 'all' ? 15 : null, color: "#FFFFFF" }} onClick={() => handleOptionChange('all')}>All</Button>
|
// top: 30,
|
||||||
<Button style={{ textTransform: "capitalize", background: selectedOption === 'revisions' ? "#494949" : "#1A1A1A", borderRadius: selectedOption === 'revisions' ? 15 : null, color: "#FFFFFF" }} onClick={() => handleOptionChange('revisions')}>Revisions</Button>
|
// transform: 'translateX(-50%)',
|
||||||
<Button style={{ textTransform: "capitalize", background: selectedOption === 'run' ? "#494949" : "#1A1A1A", borderRadius: selectedOption === 'run' ? 15 : null, color: "#FFFFFF" }} onClick={() => handleOptionChange('run')}>Runs</Button>
|
// backgroundColor: '#2f2f2f',
|
||||||
</div>
|
// borderRadius: '50%',
|
||||||
<Bar data={data} options={options} style={{ width: 400, marginLeft: 25, padding:20,marginTop: 10 }} />
|
// height: 24,
|
||||||
</div>
|
// width: 24,
|
||||||
</div>
|
// transition: 'transform 10s ease-in-out',
|
||||||
<div style={{ width: 375, height: 440, display: 'flex', alignItems: 'start', paddingTop: '16px', paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
// }}><NewReleasesIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
||||||
<div style={{ marginLeft: 18 }}>Insights</div>
|
// null
|
||||||
</div>
|
// }
|
||||||
</div>
|
// </div>
|
||||||
<div style={{ width: 985, paddingTop: 16, marginTop: 16, paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
// </Grid>
|
||||||
<div style={{ marginLeft: 18, textAlign: 'start', marginBottom: 16 }}>Sessions Overview</div>
|
// <Grid item xs={4}>
|
||||||
<div style={{ display: "flex", width: "100%", justifyContent: "center" }}>
|
// <div style={{ position: 'relative' }}>
|
||||||
<div style={{ fontSize: '16px',width: "30%", borderRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
// <img src="/images/adminpage/app1.svg" style={{ margin: 'auto' }} />
|
||||||
<div style={{ marginTop: 21, color: "#ffffff", marginLeft:20,fontSize: 16, fontWeight: "bold", }}>
|
// {checked ?
|
||||||
2.8 Hours
|
// <div style={{
|
||||||
</div>
|
// position: 'absolute',
|
||||||
<div style={{ marginTop: 13, marginBottom: 16, marginLeft:20, }}>
|
// bottom: 0,
|
||||||
Avg. Activity per session
|
// left: '50%',
|
||||||
</div>
|
// top: 30,
|
||||||
</div>
|
// transform: 'translateX(-50%)',
|
||||||
<div style={{ marginLeft: 16, fontSize: '16px', width: "30%", borderRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
// backgroundColor: '#2f2f2f',
|
||||||
<div style={{ marginTop: 21, marginLeft:20, color: "#ffffff", fontSize: 16, fontWeight: "bold", }}>
|
// borderRadius: '50%',
|
||||||
/usercases/edr to ticket
|
// height: 24,
|
||||||
</div>
|
// width: 24,
|
||||||
<div style={{ marginTop: 13, marginLeft:20, marginBottom: 16, }}>
|
// transition: 'transform 10s ease-in-out',
|
||||||
Last visited page
|
// }}><MailOutlineIcon style={{ width: 16, height: 16, marginTop: 5 }} /></div> :
|
||||||
</div>
|
// null
|
||||||
</div>
|
// }
|
||||||
<div style={{ marginLeft: 16, fontSize: '16px', width: "30%", borderRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
// </div>
|
||||||
<div style={{ marginTop: 21, marginLeft:20,color: "#ffffff", fontSize: 16, fontWeight: "bold", }}>
|
// </Grid>
|
||||||
/workflow/email management
|
// </Grid>
|
||||||
</div>
|
// </div>
|
||||||
<div style={{ marginTop: 13, marginLeft:20, marginBottom: 16, }}>
|
// </div>}
|
||||||
Most visited page
|
// </div>
|
||||||
</div>
|
// <div style={{ width: 595, height: 322, marginTop: 16, paddingTop: 16, paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
||||||
</div>
|
// <div style={{ marginLeft: 18, textAlign: "start" }}>Workflows</div>
|
||||||
</div>
|
// <div style={{textAlign:"center"}}>
|
||||||
</div>
|
// <Button style={{ textTransform: "capitalize", background: selectedOption === 'all' ? "#494949" : "#1A1A1A", borderRadius: selectedOption === 'all' ? 15 : null, color: "#FFFFFF" }} onClick={() => handleOptionChange('all')}>All</Button>
|
||||||
</div>
|
// <Button style={{ textTransform: "capitalize", background: selectedOption === 'revisions' ? "#494949" : "#1A1A1A", borderRadius: selectedOption === 'revisions' ? 15 : null, color: "#FFFFFF" }} onClick={() => handleOptionChange('revisions')}>Revisions</Button>
|
||||||
);
|
// <Button style={{ textTransform: "capitalize", background: selectedOption === 'run' ? "#494949" : "#1A1A1A", borderRadius: selectedOption === 'run' ? 15 : null, color: "#FFFFFF" }} onClick={() => handleOptionChange('run')}>Runs</Button>
|
||||||
|
// </div>
|
||||||
|
// <Bar data={data} options={options} style={{ width: 400, marginLeft: 25, padding:20,marginTop: 10 }} />
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// <div style={{ width: 375, height: 440, display: 'flex', alignItems: 'start', paddingTop: '16px', paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
||||||
|
// <div style={{ marginLeft: 18 }}>Insights</div>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// <div style={{ width: 985, paddingTop: 16, marginTop: 16, paddingBottom: '48px', fontSize: '16px', color: '#ffffff', backgroundColor: '#1A1A1A', borderRadius: '16px', }}>
|
||||||
|
// <div style={{ marginLeft: 18, textAlign: 'start', marginBottom: 16 }}>Sessions Overview</div>
|
||||||
|
// <div style={{ display: "flex", width: "100%", justifyContent: "center" }}>
|
||||||
|
// <div style={{ fontSize: '16px',width: "30%", borderRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
||||||
|
// <div style={{ marginTop: 21, color: "#ffffff", marginLeft:20,fontSize: 16, fontWeight: "bold", }}>
|
||||||
|
// 2.8 Hours
|
||||||
|
// </div>
|
||||||
|
// <div style={{ marginTop: 13, marginBottom: 16, marginLeft:20, }}>
|
||||||
|
// Avg. Activity per session
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// <div style={{ marginLeft: 16, fontSize: '16px', width: "30%", borderRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
||||||
|
// <div style={{ marginTop: 21, marginLeft:20, color: "#ffffff", fontSize: 16, fontWeight: "bold", }}>
|
||||||
|
// /usercases/edr to ticket
|
||||||
|
// </div>
|
||||||
|
// <div style={{ marginTop: 13, marginLeft:20, marginBottom: 16, }}>
|
||||||
|
// Last visited page
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// <div style={{ marginLeft: 16, fontSize: '16px', width: "30%", borderRadius: 8, background: '#212121', color: '#9CA3AF' }}>
|
||||||
|
// <div style={{ marginTop: 21, marginLeft:20,color: "#ffffff", fontSize: 16, fontWeight: "bold", }}>
|
||||||
|
// /workflow/email management
|
||||||
|
// </div>
|
||||||
|
// <div style={{ marginTop: 13, marginLeft:20, marginBottom: 16, }}>
|
||||||
|
// Most visited page
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AnalyticsTab;
|
export default AnalyticsTab;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import throttle from "lodash/throttle";
|
import throttle from "lodash/throttle";
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import { validateJson, collapseField, } from "../views/Workflows.jsx";
|
import { validateJson, collapseField, } from "../views/Workflows.jsx";
|
||||||
|
|
||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
@@ -37,6 +37,8 @@ import { Context } from "../context/ContextApi.jsx";
|
|||||||
|
|
||||||
function CustomTabPanel(props) {
|
function CustomTabPanel(props) {
|
||||||
const { children, value, index, ...other } = props;
|
const { children, value, index, ...other } = props;
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -47,7 +49,7 @@ function CustomTabPanel(props) {
|
|||||||
{...other}
|
{...other}
|
||||||
>
|
>
|
||||||
{value === index && (
|
{value === index && (
|
||||||
<Box sx={{ p: 3, padding: 0, backgroundColor: "#1a1a1a" }}>
|
<Box sx={{ p: 3, padding: 0, backgroundColor: theme.palette.backgroundColor}}>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
@@ -100,6 +102,8 @@ const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, se
|
|||||||
const [selectedActionIndex, setSelectedActionIndex] = useState(0);
|
const [selectedActionIndex, setSelectedActionIndex] = useState(0);
|
||||||
const [ExampleBody, setExampleBody] = useState({});
|
const [ExampleBody, setExampleBody] = useState({});
|
||||||
const [filteredActions, setFilteredActions] = useState([]);
|
const [filteredActions, setFilteredActions] = useState([]);
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const [firstSendDone, setFirstSendDone] = useState(false)
|
const [firstSendDone, setFirstSendDone] = useState(false)
|
||||||
|
|
||||||
@@ -1391,6 +1395,8 @@ const ActionsList = memo(({
|
|||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [visibleActions, setVisibleActions] = useState([]);
|
const [visibleActions, setVisibleActions] = useState([]);
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1457,13 +1463,13 @@ const ActionsList = memo(({
|
|||||||
<Tooltip title="Go to app" placement="right">
|
<Tooltip title="Go to app" placement="right">
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
<img
|
<img
|
||||||
src={openapi?.info["x-logo"]}
|
src={openapi?.info["x-logo"]?.length > 0 ? openapi?.info["x-logo"] : theme?.palette?.defaultImage}
|
||||||
width={48}
|
width={48}
|
||||||
height={48}
|
height={48}
|
||||||
alt="app logo"
|
alt="app logo"
|
||||||
style={{ marginLeft: 20, borderRadius: 8 }}
|
style={{ marginLeft: 20, borderRadius: 8 }}
|
||||||
/>
|
/>
|
||||||
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: '#F1F1F1'
|
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: theme.palette.textColor
|
||||||
}}>
|
}}>
|
||||||
{info.title}
|
{info.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -1471,7 +1477,7 @@ const ActionsList = memo(({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: '#F1F1F1'
|
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: theme.palette.textColor
|
||||||
}}>
|
}}>
|
||||||
Api Explorer
|
Api Explorer
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -1504,7 +1510,7 @@ const ActionsList = memo(({
|
|||||||
style={{
|
style={{
|
||||||
marginLeft: 20,
|
marginLeft: 20,
|
||||||
marginTop: 15,
|
marginTop: 15,
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
height: (isLoaded && isLoggedIn) ? "calc(100vh - 190px)" : "calc(100vh - 260px)",
|
height: (isLoaded && isLoggedIn) ? "calc(100vh - 190px)" : "calc(100vh - 260px)",
|
||||||
paddingRight: 5,
|
paddingRight: 5,
|
||||||
@@ -1522,7 +1528,7 @@ const ActionsList = memo(({
|
|||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
selectedActionIndex === actionIndex
|
selectedActionIndex === actionIndex
|
||||||
? "#3f3f3f"
|
? theme.palette.hoverColor
|
||||||
: "transparent",
|
: "transparent",
|
||||||
border: "none",
|
border: "none",
|
||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
@@ -1535,7 +1541,7 @@ const ActionsList = memo(({
|
|||||||
textWrap: "nowrap",
|
textWrap: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#2f2f2f",
|
backgroundColor: theme.palette.hoverColor,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
onClick={() => handleActionClick(actionIndex, action)}
|
onClick={() => handleActionClick(actionIndex, action)}
|
||||||
@@ -1554,7 +1560,7 @@ const ActionsList = memo(({
|
|||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
@@ -1564,7 +1570,7 @@ const ActionsList = memo(({
|
|||||||
</Button>
|
</Button>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div style={{ padding: "15px", color: "white", textAlign: "center" }}>
|
<div style={{ padding: "15px", color: theme.palette.textColor, textAlign: "center" }}>
|
||||||
No actions found
|
No actions found
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1602,6 +1608,8 @@ const Action = memo((
|
|||||||
const [disableExecuteButton, setDisableExecuteButton] = useState(false);
|
const [disableExecuteButton, setDisableExecuteButton] = useState(false);
|
||||||
const [showResponseLoader, setShowResponseLoader] = useState(false);
|
const [showResponseLoader, setShowResponseLoader] = useState(false);
|
||||||
const [appAuthentication, setAppAuthentication] = useState([])
|
const [appAuthentication, setAppAuthentication] = useState([])
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
const parseHeaders = (headersString) => {
|
const parseHeaders = (headersString) => {
|
||||||
if (headersString?.length > 0) {
|
if (headersString?.length > 0) {
|
||||||
const headersArray = headersString.split("\n");
|
const headersArray = headersString.split("\n");
|
||||||
@@ -2082,7 +2090,7 @@ const Action = memo((
|
|||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
marginLeft: 40,
|
marginLeft: 40,
|
||||||
marginBottom: 5,
|
marginBottom: 5,
|
||||||
color: "rgba(241, 241, 241, 1)",
|
color: theme.palette.textColor
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{actionname}
|
{actionname}
|
||||||
@@ -2095,7 +2103,7 @@ const Action = memo((
|
|||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
marginLeft: "40px",
|
marginLeft: "40px",
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
height: 51,
|
height: 51,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
@@ -2109,7 +2117,7 @@ const Action = memo((
|
|||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
"& .MuiSelect-select": {
|
"& .MuiSelect-select": {
|
||||||
color: RequestMethods.find((method) => method.value === selectedMethod)
|
color: RequestMethods.find((method) => method.value === selectedMethod)
|
||||||
?.color || "#212121",
|
?.color || theme.palette.textFieldStyle.backgroundColor,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
MenuProps={{
|
MenuProps={{
|
||||||
@@ -2117,14 +2125,14 @@ const Action = memo((
|
|||||||
sx: {
|
sx: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MenuListProps: {
|
MenuListProps: {
|
||||||
sx: {
|
sx: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -2135,20 +2143,20 @@ const Action = memo((
|
|||||||
value={method.value}
|
value={method.value}
|
||||||
sx={{
|
sx={{
|
||||||
color: method.color,
|
color: method.color,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
border: "none",
|
border: "none",
|
||||||
marginBottom: 0.25,
|
marginBottom: 0.25,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: method.color,
|
backgroundColor: method.color,
|
||||||
color: "#f9fcf5",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
backgroundColor: method.color,
|
backgroundColor: method.color,
|
||||||
color: "#f9fcf5",
|
color: theme.palette.textFieldStyle.color,
|
||||||
border: "none",
|
border: "none",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: method.color,
|
backgroundColor: method.color,
|
||||||
color: "#f9fcf5",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"&.Mui-focusVisible": {
|
"&.Mui-focusVisible": {
|
||||||
@@ -2167,9 +2175,8 @@ const Action = memo((
|
|||||||
inputProps={{
|
inputProps={{
|
||||||
style: {
|
style: {
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
backgroundColor: "transparent",
|
|
||||||
border: "none",
|
border: "none",
|
||||||
color: "rgba(241, 241, 241, 1)",
|
color: theme.palette.textFieldStyle.color,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -2331,7 +2338,7 @@ const Action = memo((
|
|||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
background: "rgba(26, 26, 26, 1)",
|
background: theme.palette.backgroundColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
@@ -2386,7 +2393,7 @@ const Action = memo((
|
|||||||
<TableContainer
|
<TableContainer
|
||||||
style={{
|
style={{
|
||||||
minWidth: 696,
|
minWidth: 696,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
border: "1px solid rgba(73, 73, 73, 1)",
|
border: "1px solid rgba(73, 73, 73, 1)",
|
||||||
}}
|
}}
|
||||||
@@ -2436,7 +2443,7 @@ const Action = memo((
|
|||||||
}
|
}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgba(33, 33, 33, 1)",
|
backgroundColor: theme.palette.platformColor,
|
||||||
padding: "4px 8px",
|
padding: "4px 8px",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -2494,7 +2501,7 @@ const Action = memo((
|
|||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
),
|
),
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgba(33, 33, 33, 1)",
|
backgroundColor: theme.palette.platformColor,
|
||||||
padding: "4px 8px",
|
padding: "4px 8px",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -2600,7 +2607,7 @@ const Action = memo((
|
|||||||
<TableContainer
|
<TableContainer
|
||||||
style={{
|
style={{
|
||||||
minWidth: 696,
|
minWidth: 696,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
border: "1px solid rgba(73, 73, 73, 1)",
|
border: "1px solid rgba(73, 73, 73, 1)",
|
||||||
}}
|
}}
|
||||||
@@ -2640,7 +2647,7 @@ const Action = memo((
|
|||||||
type="text"
|
type="text"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgba(33, 33, 33, 1)",
|
backgroundColor: theme.palette.platformColor ,
|
||||||
padding: "4px 8px",
|
padding: "4px 8px",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -2694,7 +2701,7 @@ const Action = memo((
|
|||||||
value={row.value}
|
value={row.value}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgba(33, 33, 33, 1)",
|
backgroundColor: theme.palette.platformColor,
|
||||||
padding: "4px 8px",
|
padding: "4px 8px",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -2794,10 +2801,10 @@ const Action = memo((
|
|||||||
marginLeft: 10
|
marginLeft: 10
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16, fontWeight: 600 }}>
|
<span style={{ fontSize: 16, fontWeight: 600, color: theme.palette.textColor }}>
|
||||||
{action.name.replaceAll("_", " ")}
|
{action.name.replaceAll("_", " ")}
|
||||||
</span>
|
</span>
|
||||||
<p >
|
<p style={{color: theme.palette.textColor}}>
|
||||||
{action.description
|
{action.description
|
||||||
? action.description
|
? action.description
|
||||||
: ""}
|
: ""}
|
||||||
@@ -2813,6 +2820,8 @@ const ActionResponse = memo(({ apiResponse, ExampleBody, isLoggedIn, isLoaded })
|
|||||||
const [responseTabIndex, setResponseTabIndex] = useState(0)
|
const [responseTabIndex, setResponseTabIndex] = useState(0)
|
||||||
const [oldResponse, setOldResponse] = useState(apiResponse)
|
const [oldResponse, setOldResponse] = useState(apiResponse)
|
||||||
const [highlight, setHighlight] = useState(false)
|
const [highlight, setHighlight] = useState(false)
|
||||||
|
const {themeMode } = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const MIN_HEIGHT = 50
|
const MIN_HEIGHT = 50
|
||||||
|
|
||||||
@@ -2934,7 +2943,7 @@ const ActionResponse = memo(({ apiResponse, ExampleBody, isLoggedIn, isLoaded })
|
|||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: height,
|
height: height,
|
||||||
backgroundColor: '#1a1a1a',
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
borderTop: '1px solid rgba(255,255,255,0.2)',
|
borderTop: '1px solid rgba(255,255,255,0.2)',
|
||||||
@@ -2988,7 +2997,7 @@ const ActionResponse = memo(({ apiResponse, ExampleBody, isLoggedIn, isLoaded })
|
|||||||
<ReactJson
|
<ReactJson
|
||||||
src={formData(ExampleBody)}
|
src={formData(ExampleBody)}
|
||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={{ backgroundColor: '#1a1a1a', padding: 5 }}
|
style={{...theme.palette.reactJsonStyle, border: "none"}}
|
||||||
collapsed={false}
|
collapsed={false}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
@@ -3005,6 +3014,10 @@ const ActionResponse = memo(({ apiResponse, ExampleBody, isLoggedIn, isLoaded })
|
|||||||
});
|
});
|
||||||
|
|
||||||
const ResponseTabWrapper = memo(({ apiResponse }) => {
|
const ResponseTabWrapper = memo(({ apiResponse }) => {
|
||||||
|
|
||||||
|
const {themeMode } = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const handleReactJsonClipboard = (copy) => {
|
const handleReactJsonClipboard = (copy) => {
|
||||||
const elementName = "copy_element_shuffle";
|
const elementName = "copy_element_shuffle";
|
||||||
let copyText = document.getElementById(elementName);
|
let copyText = document.getElementById(elementName);
|
||||||
@@ -3036,7 +3049,7 @@ const ResponseTabWrapper = memo(({ apiResponse }) => {
|
|||||||
<ReactJson
|
<ReactJson
|
||||||
src={apiResponse}
|
src={apiResponse}
|
||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={{ backgroundColor: "#1a1a1a", padding: 5 }}
|
style={{...theme.palette.reactJsonStyle, border: "none"}}
|
||||||
shouldCollapse={(jsonField) => {
|
shouldCollapse={(jsonField) => {
|
||||||
return collapseField(jsonField)
|
return collapseField(jsonField)
|
||||||
}}
|
}}
|
||||||
@@ -3049,7 +3062,8 @@ const ResponseTabWrapper = memo(({ apiResponse }) => {
|
|||||||
)})
|
)})
|
||||||
|
|
||||||
const PaddingWrapper = memo(({ isLoggedIn, isLoaded, children }) => {
|
const PaddingWrapper = memo(({ isLoggedIn, isLoaded, children }) => {
|
||||||
const { leftSideBarOpenByClick, windowWidth } = useContext(Context);
|
const { leftSideBarOpenByClick, windowWidth, themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -3058,7 +3072,7 @@ const PaddingWrapper = memo(({ isLoggedIn, isLoaded, children }) => {
|
|||||||
? windowWidth >= 1920 ? "calc(100% - 630px)" : "calc(100% - 570px)"
|
? windowWidth >= 1920 ? "calc(100% - 630px)" : "calc(100% - 570px)"
|
||||||
: windowWidth >= 1920 ? "calc(100vw - 460px)": "calc(100% - 410px)"
|
: windowWidth >= 1920 ? "calc(100vw - 460px)": "calc(100% - 410px)"
|
||||||
: windowWidth >= 1920 ? "calc(100% - 370px)" : "calc(100% - 320px)",
|
: windowWidth >= 1920 ? "calc(100% - 370px)" : "calc(100% - 320px)",
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
||||||
import { isMobile } from "react-device-detect"
|
import { isMobile } from "react-device-detect"
|
||||||
@@ -66,7 +66,7 @@ import { Context } from '../context/ContextApi.jsx';
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
)
|
)
|
||||||
|
|
||||||
const AppAuthTab = memo((props) => {
|
const AppAuthTab = memo((props) => {
|
||||||
@@ -83,16 +83,17 @@ const AppAuthTab = memo((props) => {
|
|||||||
const [appAuthenticationGroupId, setAppAuthenticationGroupId] = React.useState("");
|
const [appAuthenticationGroupId, setAppAuthenticationGroupId] = React.useState("");
|
||||||
const [appAuthenticationGroups, setAppAuthenticationGroups] = React.useState([]);
|
const [appAuthenticationGroups, setAppAuthenticationGroups] = React.useState([]);
|
||||||
const [appAuthenticationGroupName, setAppAuthenticationGroupName] = React.useState("");
|
const [appAuthenticationGroupName, setAppAuthenticationGroupName] = React.useState("");
|
||||||
|
const [selectedSubOrg, setSelectedSubOrg] = useState([]);
|
||||||
const [appAuthenticationGroupDescription, setAppAuthenticationGroupDescription] = React.useState("");
|
const [appAuthenticationGroupDescription, setAppAuthenticationGroupDescription] = React.useState("");
|
||||||
const [appsForAppAuthGroup, setAppsForAppAuthGroup] = React.useState([]);
|
const [appsForAppAuthGroup, setAppsForAppAuthGroup] = React.useState([]);
|
||||||
const [searchQuery, setSearchQuery] = React.useState("");
|
const [searchQuery, setSearchQuery] = React.useState("");
|
||||||
const [showAppModal, setShowAppModal] = useState(false)
|
const [showAppModal, setShowAppModal] = useState(false)
|
||||||
|
const [selectedAuthId, setSelectedAuthId] = useState("");
|
||||||
|
const [showDistributionPopup, setShowDistributionPopup] = useState(false);
|
||||||
const [showAuthenticationLoader, setShowAuthenticationLoader] = useState(true)
|
const [showAuthenticationLoader, setShowAuthenticationLoader] = useState(true)
|
||||||
const [showAppAuthGroupLoader, setShowAppAuthGroupLoader] = useState(true)
|
const [showAppAuthGroupLoader, setShowAppAuthGroupLoader] = useState(true)
|
||||||
const changeDistribution = (data) => {
|
const { themeMode, supportEmail, brandColor } = useContext(Context)
|
||||||
//changeDistributed(data, !isDistributed)
|
const theme = getTheme(themeMode, brandColor)
|
||||||
editAuthenticationConfig(data.id, "suborg_distribute")
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getAppAuthentication();
|
getAppAuthentication();
|
||||||
@@ -212,11 +213,39 @@ const AppAuthTab = memo((props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const editAuthenticationConfig = (id, parentAction) => {
|
const handleSelectSubOrg = (id, action) => {
|
||||||
|
if (action === "all") {
|
||||||
|
const childOrgs = userdata.orgs.filter(
|
||||||
|
(data) => data.creator_org === userdata.active_org.id
|
||||||
|
);
|
||||||
|
setSelectedSubOrg((prev) => {
|
||||||
|
if (prev.length === childOrgs.length) {
|
||||||
|
// If all child orgs are already selected, clear the selection
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
// Otherwise, select all child org IDs
|
||||||
|
return childOrgs.map((data) => data.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (action === "none") {
|
||||||
|
setSelectedSubOrg([]);
|
||||||
|
} else {
|
||||||
|
setSelectedSubOrg((prev) => {
|
||||||
|
if (prev.includes(id)) {
|
||||||
|
return prev.filter((data) => data !== id);
|
||||||
|
} else {
|
||||||
|
return [...prev, id];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const editAuthenticationConfig = (id, parentAction, selectedSuborgs) => {
|
||||||
const data = {
|
const data = {
|
||||||
id: id,
|
id: id,
|
||||||
action: parentAction !== undefined && parentAction !== null ? parentAction : "assign_everywhere",
|
action: parentAction !== undefined && parentAction !== null ? parentAction : "assign_everywhere",
|
||||||
}
|
selected_suborgs: selectedSuborgs !== undefined && selectedSuborgs !== null ? selectedSuborgs : [],
|
||||||
|
}
|
||||||
|
|
||||||
const url = globalUrl + "/api/v1/apps/authentication/" + id + "/config";
|
const url = globalUrl + "/api/v1/apps/authentication/" + id + "/config";
|
||||||
|
|
||||||
@@ -238,6 +267,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
} else {
|
} else {
|
||||||
toast("Successfully updated auth!");
|
toast("Successfully updated auth!");
|
||||||
setSelectedUserModalOpen(false);
|
setSelectedUserModalOpen(false);
|
||||||
|
setShowDistributionPopup(false);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getAppAuthentication();
|
getAppAuthentication();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -249,6 +279,106 @@ const AppAuthTab = memo((props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const changeDistribution = (id, selectedSubOrg) => {
|
||||||
|
|
||||||
|
editAuthenticationConfig(id, "suborg_distribute", [...new Set(selectedSubOrg)])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const cacheDistributionModal = showDistributionPopup ? (
|
||||||
|
<Dialog
|
||||||
|
open={showDistributionPopup}
|
||||||
|
onClose={() => {setShowDistributionPopup(false);setSelectedAuthId("")}}
|
||||||
|
PaperProps={{
|
||||||
|
sx: {
|
||||||
|
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
|
||||||
|
border: theme?.palette?.DialogStyle?.border,
|
||||||
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
zIndex: 1000,
|
||||||
|
minWidth: "600px",
|
||||||
|
minHeight: "320px",
|
||||||
|
overflow: "auto",
|
||||||
|
'& .MuiDialogContent-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
'& .MuiDialogTitle-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
'& .MuiDialogActions-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<Typography variant="h5" color="textPrimary">
|
||||||
|
Select sub-org to distribute Datastore key
|
||||||
|
</Typography>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
|
||||||
|
<MenuItem value="none" onClick={()=> {handleSelectSubOrg(null, "none")}}>None</MenuItem>
|
||||||
|
<MenuItem value="all" onClick={()=> {handleSelectSubOrg(null, "all")}}>All</MenuItem>
|
||||||
|
{userdata.orgs.map((data, index) => {
|
||||||
|
if (data.creator_org !== userdata.active_org.id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imagesize = 22;
|
||||||
|
const imageStyle = {
|
||||||
|
width: imagesize,
|
||||||
|
height: imagesize,
|
||||||
|
pointerEvents: "none",
|
||||||
|
marginRight: 10,
|
||||||
|
marginLeft: data.id === userdata.active_org.id ? 0 : 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const image = data.image === "" ? (
|
||||||
|
<img alt={data.name} src={theme.palette.defaultImage} style={imageStyle} />
|
||||||
|
) : (
|
||||||
|
<img alt={data.name} src={data.image} style={imageStyle} />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={index}
|
||||||
|
value={data.id}
|
||||||
|
onClick={() => handleSelectSubOrg(data.id)}
|
||||||
|
style={{ display: "flex", alignItems: "center" }}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={selectedSubOrg.includes(data.id)}
|
||||||
|
/>
|
||||||
|
{image}
|
||||||
|
<span style={{ marginLeft: 8 }}>{data.name}</span>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<div style={{ display: "flex", marginTop: 20 }}>
|
||||||
|
<Button
|
||||||
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: theme.palette.primary.main }}
|
||||||
|
onClick={() => {setShowDistributionPopup(false); setSelectedAuthId("")}}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, marginLeft: 10 }}
|
||||||
|
onClick={() => {
|
||||||
|
changeDistribution(selectedAuthId, selectedSubOrg);
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
) : null;
|
||||||
|
|
||||||
const editAuthenticationModal = selectedAuthenticationModalOpen ? (
|
const editAuthenticationModal = selectedAuthenticationModalOpen ? (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={selectedAuthenticationModalOpen}
|
open={selectedAuthenticationModalOpen}
|
||||||
@@ -277,7 +407,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<span style={{ color: "white" }}>
|
<span style={{ color: theme.palette.textColor }}>
|
||||||
Edit authentication for {selectedAuthentication.app.name.replaceAll("_", " ")} (
|
Edit authentication for {selectedAuthentication.app.name.replaceAll("_", " ")} (
|
||||||
{selectedAuthentication.label})
|
{selectedAuthentication.label})
|
||||||
</span>
|
</span>
|
||||||
@@ -297,7 +427,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 50,
|
height: 50,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -349,7 +479,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 50,
|
height: 50,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -568,7 +698,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
toast("Failed to create. Please try again, or contact support@shuffler.io")
|
toast(`Failed to create. Please try again, or contact ${supportEmail}`)
|
||||||
} else {
|
} else {
|
||||||
// Close the modal
|
// Close the modal
|
||||||
setAppAuthenticationGroupModalOpen(false)
|
setAppAuthenticationGroupModalOpen(false)
|
||||||
@@ -660,7 +790,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<span style={{ color: "white" }}>App Authentication Groups</span>
|
<span style={{ color: theme.palette.textColor }}>App Authentication Groups</span>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<DialogContent style={{marginLeft: 0, paddingLeft: 0, }}>
|
<DialogContent style={{marginLeft: 0, paddingLeft: 0, }}>
|
||||||
@@ -677,7 +807,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: "50px",
|
height: "50px",
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -842,7 +972,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
hitsPerPage={5}
|
hitsPerPage={5}
|
||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
isCloud={isCloud}
|
isCloud={isCloud !== true}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
getAppAuthentication={getAppAuthentication}
|
getAppAuthentication={getAppAuthentication}
|
||||||
/>
|
/>
|
||||||
@@ -853,35 +983,40 @@ const AppAuthTab = memo((props) => {
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{width: "100%", minHeight: 1100, maxHeight: 1700, overflowY: "auto", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin',boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: '#212121',borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", }}>
|
<div style={{width: "100%", minHeight: 1100, maxHeight: 1700, overflowY: "auto", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin',boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor,borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: theme.palette.defaultBorder, }}>
|
||||||
{appModal}
|
{appModal}
|
||||||
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
|
{cacheDistributionModal}
|
||||||
|
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
|
||||||
<div style={{ width: 'auto', display:'flex',}}>
|
<div style={{ width: 'auto', display:'flex',}}>
|
||||||
<div style={{display: 'flex', flexDirection: 'column'}}>
|
<div style={{display: 'flex', flexDirection: 'column'}}>
|
||||||
<h2 style={{ marginBottom: 8, marginTop: 0, color: "#FFFFFF" }}>App Authentication</h2>
|
<Typography variant='h5' style={{ marginBottom: 8, marginTop: 0, }}>App Authentication</Typography>
|
||||||
<div>
|
<div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', }}>
|
||||||
<span style={{}}>
|
<Typography variant='body2' color="textSecondary">
|
||||||
Control the authentication options for individual apps.
|
Control the authentication options for individual apps.
|
||||||
</span>
|
</Typography>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/organizations#app_authentication"
|
href="/docs/organizations#app_authentication"
|
||||||
style={{ color: "#FF8444" }}
|
style={{ color: theme.palette.linkColor }}
|
||||||
>
|
>
|
||||||
Learn more about App Authentication
|
Learn more about App Authentication
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
|
||||||
style={{ color: '#1a1a1a', textTransform: 'none', backgroundColor: "#FF8444", marginLeft:"auto", borderRadius: 4,fontSize: 16, minWidth: 162, height: 40, boxShadow:'none', }}
|
{isCloud ?
|
||||||
variant="contained"
|
<Button
|
||||||
color="primary"
|
style={{ textTransform: 'none', marginLeft:"auto", borderRadius: 4,fontSize: 16, minWidth: 162, height: 40, boxShadow:'none', }}
|
||||||
onClick={() => setShowAppModal(true)}
|
variant="contained"
|
||||||
>
|
color="primary"
|
||||||
Add App Auth
|
disabled={!isCloud}
|
||||||
</Button>
|
onClick={() => setShowAppModal(true)}
|
||||||
|
>
|
||||||
|
Add App Auth
|
||||||
|
</Button>
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
{/* <Divider
|
{/* <Divider
|
||||||
style={{
|
style={{
|
||||||
@@ -895,7 +1030,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -913,7 +1048,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
}}>
|
}}>
|
||||||
|
|
||||||
|
|
||||||
<ListItem style={{ width: "100%", paddingTop: 10, paddingBottom: 10, paddingRight: 10, borderBottom: "1px solid #494949", display: 'table-row'}}>
|
<ListItem style={{ width: "100%", paddingTop: 10, paddingBottom: 10, paddingRight: 10, borderBottom: theme.palette.defaultBorder, display: 'table-row'}}>
|
||||||
|
|
||||||
{["Valid", "Label", "App Name", "Workflows", "Fields", "Edited", "Actions", "Distribution"].map((header, index) => (
|
{["Valid", "Label", "App Name", "Workflows", "Fields", "Edited", "Actions", "Distribution"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
@@ -924,7 +1059,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -938,7 +1073,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
key={rowIndex}
|
key={rowIndex}
|
||||||
style={{
|
style={{
|
||||||
display: "table-row",
|
display: "table-row",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(8)
|
{Array(8)
|
||||||
@@ -955,7 +1090,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
height: "20px",
|
height: "20px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
@@ -966,14 +1101,14 @@ const AppAuthTab = memo((props) => {
|
|||||||
))
|
))
|
||||||
: authentication?.length === 0 ? (
|
: authentication?.length === 0 ? (
|
||||||
<div style={{ textAlign: 'center'}}>
|
<div style={{ textAlign: 'center'}}>
|
||||||
<Typography style={{ color: "#FFFFFF", textAlign: 'center', padding: 20}}>
|
<Typography color="textPrimary" style={{ textAlign: 'center', padding: 20}}>
|
||||||
No authentication found.
|
No authentication found.
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
):authentication.map((data, index) => {
|
):authentication.map((data, index) => {
|
||||||
var bgColor = "#212121";
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = "#1A1A1A";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("Auth data: ", data)
|
//console.log("Auth data: ", data)
|
||||||
@@ -998,7 +1133,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDistributed = data.suborg_distributed === true ? true : false;
|
const isDistributed = data?.suborg_distribution?.length > 0 || data?.suborg_distributed ? true : false;
|
||||||
var validIcon = <CheckCircleIcon style={{ color: "green" }} />
|
var validIcon = <CheckCircleIcon style={{ color: "green" }} />
|
||||||
if (data.validation !== null && data.validation !== undefined && data.validation.valid === false) {
|
if (data.validation !== null && data.validation !== undefined && data.validation.valid === false) {
|
||||||
|
|
||||||
@@ -1055,7 +1190,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
<Tooltip title={"Try the app in our API explorer"} placement="top">
|
<Tooltip title={"Try the app in our API explorer"} placement="top">
|
||||||
<a href={`/apis/${data.app.id}`} style={{ color: "#FF8444", textDecoration: "none", cursor: "pointer", }} target="_blank" rel="noopener noreferrer">
|
<a href={`/apis/${data.app.id}`} style={{ color: theme.palette.linkColor, textDecoration: "none", cursor: "pointer", }} target="_blank" rel="noopener noreferrer">
|
||||||
{data?.app?.name?.replaceAll("_", " ")}
|
{data?.app?.name?.replaceAll("_", " ")}
|
||||||
</a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1108,14 +1243,14 @@ const AppAuthTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
display: "table-cell",
|
display: "table-cell",
|
||||||
verticalAlign: 'middle'
|
verticalAlign: 'middle',
|
||||||
}}
|
}}
|
||||||
primaryTypographyProps={{
|
primaryTypographyProps={{
|
||||||
style: {
|
style: {
|
||||||
padding: 8
|
padding: 8
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
primary={new Date(data.edited * 1000).toISOString()}
|
primary={new Date(data.edited * 1000).toISOString()}
|
||||||
/>
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
style={{
|
style={{
|
||||||
@@ -1125,13 +1260,24 @@ const AppAuthTab = memo((props) => {
|
|||||||
primaryTypographyProps={{ style: { display: "flex", flexDirection: 'row', padding: 8 } }}
|
primaryTypographyProps={{ style: { display: "flex", flexDirection: 'row', padding: 8 } }}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => updateAppAuthentication(data)}
|
||||||
updateAppAuthentication(data);
|
disabled={data.org_id !== selectedOrganization.id}
|
||||||
}}
|
>
|
||||||
disabled={data.org_id !== selectedOrganization.id}
|
<svg
|
||||||
>
|
width="24"
|
||||||
<img src="/icons/editIcon.svg" alt="Edit icon" color="secondary" />
|
height="24"
|
||||||
</IconButton>
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.1038 4.66848C16.3158 4.45654 16.5674 4.28843 16.8443 4.17373C17.1212 4.05903 17.418 4 17.7177 4C18.0174 4 18.3142 4.05903 18.5911 4.17373C18.868 4.28843 19.1196 4.45654 19.3315 4.66848C19.5435 4.88041 19.7116 5.13201 19.8263 5.40891C19.941 5.68582 20 5.9826 20 6.28232C20 6.58204 19.941 6.87882 19.8263 7.15573C19.7116 7.43263 19.5435 7.68423 19.3315 7.89617L8.43807 18.7896L4 20L5.21038 15.5619L16.1038 4.66848Z"
|
||||||
|
stroke={themeMode=== "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</IconButton>
|
||||||
{data.defined ? (
|
{data.defined ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -1147,7 +1293,7 @@ const AppAuthTab = memo((props) => {
|
|||||||
editAuthenticationConfig(data.id);
|
editAuthenticationConfig(data.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectAllIcon color="secondary" />
|
<SelectAllIcon color="textSecondary" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
@@ -1164,6 +1310,47 @@ const AppAuthTab = memo((props) => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
<Tooltip
|
||||||
|
title={"Copy Auth ID"}
|
||||||
|
style={{}}
|
||||||
|
aria-label={"copy"}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
style = {{padding: "6px"}}
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(data.id);
|
||||||
|
document.execCommand("copy");
|
||||||
|
|
||||||
|
toast(data.id + " copied to clipboard");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fillOpacity="1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 4H7.6C7.17565 4 6.76869 4.16857 6.46863 4.46863C6.16857 4.76869 6 5.17565 6 5.6V18.4C6 18.8243 6.16857 19.2313 6.46863 19.5314C6.76869 19.8314 7.17565 20 7.6 20H17.2C17.6243 20 18.0313 19.8314 18.3314 19.5314C18.6314 19.2313 18.8 18.8243 18.8 18.4V8.8L14 4Z"
|
||||||
|
stroke={themeMode === "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 4V8.8H18.8"
|
||||||
|
stroke={themeMode === "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={{ }}
|
style={{ }}
|
||||||
disabled={data.org_id !== selectedOrganization.id}
|
disabled={data.org_id !== selectedOrganization.id}
|
||||||
@@ -1202,7 +1389,23 @@ const AppAuthTab = memo((props) => {
|
|||||||
style={{ }}
|
style={{ }}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
changeDistribution(data, !isDistributed)
|
setShowDistributionPopup(true)
|
||||||
|
if(data?.suborg_distribution?.length > 0){
|
||||||
|
setSelectedSubOrg(data.suborg_distribution)
|
||||||
|
}else{
|
||||||
|
setSelectedSubOrg([])
|
||||||
|
}
|
||||||
|
setSelectedAuthId(data.id)
|
||||||
|
if (data?.suborg_distributed) {
|
||||||
|
const allSuborg = userdata?.orgs?.map((data, index) => {
|
||||||
|
if (data.creator_org !== userdata.active_org.id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data.id;
|
||||||
|
})
|
||||||
|
setSelectedSubOrg(allSuborg.filter((data) => data !== null))
|
||||||
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1216,6 +1419,8 @@ const AppAuthTab = memo((props) => {
|
|||||||
{editAuthenticationModal}
|
{editAuthenticationModal}
|
||||||
{authenticationView}
|
{authenticationView}
|
||||||
<div style={{marginTop: 50, }}>
|
<div style={{marginTop: 50, }}>
|
||||||
|
|
||||||
|
{/*
|
||||||
<div style={{ marginTop: 150, marginBottom: 20 }}>
|
<div style={{ marginTop: 150, marginBottom: 20 }}>
|
||||||
<h2 style={{ color: "#FFFFFF" }}>App Authentication Groups</h2>
|
<h2 style={{ color: "#FFFFFF" }}>App Authentication Groups</h2>
|
||||||
<span style={{ marginLeft: 0 }}>
|
<span style={{ marginLeft: 0 }}>
|
||||||
@@ -1414,13 +1619,14 @@ const AppAuthTab = memo((props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1432,6 +1638,9 @@ const SearchBox = ({ currentRefinement, refine, isSearchStalled, searchQuery, se
|
|||||||
refine(searchQuery.trim());
|
refine(searchQuery.trim());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { themeMode, supportEmail } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form noValidate action="" role="search">
|
<form noValidate action="" role="search">
|
||||||
<TextField
|
<TextField
|
||||||
@@ -1445,7 +1654,7 @@ const SearchBox = ({ currentRefinement, refine, isSearchStalled, searchQuery, se
|
|||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
height: 50,
|
height: 50,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
@@ -1461,7 +1670,7 @@ const SearchBox = ({ currentRefinement, refine, isSearchStalled, searchQuery, se
|
|||||||
{searchQuery?.length > 0 && (
|
{searchQuery?.length > 0 && (
|
||||||
<ClearIcon
|
<ClearIcon
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
marginRight: 10
|
marginRight: 10
|
||||||
}}
|
}}
|
||||||
@@ -1478,7 +1687,7 @@ const SearchBox = ({ currentRefinement, refine, isSearchStalled, searchQuery, se
|
|||||||
style={{
|
style={{
|
||||||
backgroundImage:
|
backgroundImage:
|
||||||
"linear-gradient(to right, rgb(248, 106, 62), rgb(243, 64, 121))",
|
"linear-gradient(to right, rgb(248, 106, 62), rgb(243, 64, 121))",
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
border: "none",
|
border: "none",
|
||||||
padding: "10px 20px",
|
padding: "10px 20px",
|
||||||
width: 100,
|
width: 100,
|
||||||
@@ -1516,8 +1725,6 @@ const SearchBox = ({ currentRefinement, refine, isSearchStalled, searchQuery, se
|
|||||||
|
|
||||||
const Hits = ({
|
const Hits = ({
|
||||||
hits,
|
hits,
|
||||||
insights,
|
|
||||||
setIsAnyAppActivated,
|
|
||||||
searchQuery,
|
searchQuery,
|
||||||
isCloud,
|
isCloud,
|
||||||
globalUrl,
|
globalUrl,
|
||||||
@@ -1541,6 +1748,8 @@ const Hits = ({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { themeMode, supportEmail } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
const normalizedString = (name) => {
|
const normalizedString = (name) => {
|
||||||
if (typeof name === 'string') {
|
if (typeof name === 'string') {
|
||||||
@@ -1725,7 +1934,7 @@ const Hits = ({
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
toast.error("Failed to get app data or App doesn't. Please contact support@shuffler.io");
|
toast.error(`Failed to get app data or App doesn't. Please contact ${supportEmail}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
@@ -1943,7 +2152,7 @@ const Hits = ({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<DialogTitle id="draggable-dialog-title" style={{ cursor: "move", }}>
|
<DialogTitle id="draggable-dialog-title" style={{ cursor: "move", }}>
|
||||||
<div style={{ color: "white" }}>
|
<div style={{ color: theme.palette.textColor }}>
|
||||||
Authentication for {selectedApp.name.replaceAll("_", " ", -1)}
|
Authentication for {selectedApp.name.replaceAll("_", " ", -1)}
|
||||||
</div>
|
</div>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
@@ -2013,7 +2222,7 @@ const Hits = ({
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.surfaceColor,
|
backgroundColor: theme.palette.surfaceColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
height: 50,
|
height: 50,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -2021,7 +2230,7 @@ const Hits = ({
|
|||||||
key={"false"}
|
key={"false"}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
}}
|
}}
|
||||||
value={"false"}
|
value={"false"}
|
||||||
>
|
>
|
||||||
@@ -2031,7 +2240,7 @@ const Hits = ({
|
|||||||
key={"true"}
|
key={"true"}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
}}
|
}}
|
||||||
value={"true"}
|
value={"true"}
|
||||||
>
|
>
|
||||||
@@ -2110,7 +2319,7 @@ const Hits = ({
|
|||||||
PaperProps={{
|
PaperProps={{
|
||||||
style: {
|
style: {
|
||||||
pointerEvents: "auto",
|
pointerEvents: "auto",
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
minWidth: 1100,
|
minWidth: 1100,
|
||||||
minHeight: 700,
|
minHeight: 700,
|
||||||
maxHeight: 700,
|
maxHeight: 700,
|
||||||
@@ -2392,7 +2601,7 @@ const Hits = ({
|
|||||||
href={selectedMeta.link}
|
href={selectedMeta.link}
|
||||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||||
>
|
>
|
||||||
<Button style={{ color: "white", }} variant="outlined" color="secondary">
|
<Button style={{ color: theme.palette.textColor, }} variant="outlined" color="secondary">
|
||||||
<EditIcon /> Edit
|
<EditIcon /> Edit
|
||||||
</Button>
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
@@ -2403,7 +2612,7 @@ const Hits = ({
|
|||||||
style={{
|
style={{
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: 1,
|
width: 1,
|
||||||
backgroundColor: "white",
|
backgroundColor: theme.palette.textColor,
|
||||||
marginLeft: 50,
|
marginLeft: 50,
|
||||||
marginRight: 50,
|
marginRight: 50,
|
||||||
}}
|
}}
|
||||||
@@ -2498,7 +2707,7 @@ const Hits = ({
|
|||||||
height: 480,
|
height: 480,
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
scrollbarWidth: "thin",
|
scrollbarWidth: "thin",
|
||||||
scrollbarColor: "#494949 #2f2f2f",
|
scrollbarColor: theme.palette.scrollbarColor,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -2529,7 +2738,7 @@ const Hits = ({
|
|||||||
elevation={0}
|
elevation={0}
|
||||||
style={{
|
style={{
|
||||||
...paperStyle,
|
...paperStyle,
|
||||||
backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "rgba(26, 26, 26, 1)",
|
backgroundColor: mouseHoverIndex === index ? theme.palette.cardHoverColor : theme.palette.cardBackgroundColor,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={() => setMouseHoverIndex(index)}
|
onMouseEnter={() => setMouseHoverIndex(index)}
|
||||||
@@ -2588,7 +2797,7 @@ const Hits = ({
|
|||||||
gap: 8,
|
gap: 8,
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
color: "#F1F1F1",
|
color: theme.palette.textColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{normalizedString(data.name)}
|
{normalizedString(data.name)}
|
||||||
@@ -2631,7 +2840,7 @@ const Hits = ({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button style={{position: 'relative', borderRadius: 6, bottom: 10, marginRight: 10, fontSize: 16, backgroundColor: '#ff8544', color: "#1a1a1a", textTransform:'none', marginLeft: 'auto'}} onClick={(e)=> {e.preventDefault();e.stopPropagation();handleAppAuthenticationNew(data)()}}>
|
<Button variant='contained' color='primary' style={{position: 'relative', borderRadius: 6, bottom: 10, marginRight: 10, fontSize: 16, textTransform:'none', marginLeft: 'auto'}} onClick={(e)=> {e.preventDefault();e.stopPropagation();handleAppAuthenticationNew(data)()}}>
|
||||||
Authenticate app
|
Authenticate app
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import CreateIcon from '@mui/icons-material/Create'
|
|||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import YAML from "yaml";
|
import YAML from "yaml";
|
||||||
|
|
||||||
|
|
||||||
const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
||||||
const [openApiModal, setOpenApiModal] = useState(false)
|
const [openApiModal, setOpenApiModal] = useState(false)
|
||||||
const [generateAppModal, setGenerateAppModal] = useState(false)
|
const [generateAppModal, setGenerateAppModal] = useState(false)
|
||||||
@@ -43,9 +42,8 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
|
|
||||||
const parsedStyle = {
|
const parsedStyle = {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
padding: 20,
|
padding: "30px 20px 20px",
|
||||||
margin: 12,
|
margin: 12,
|
||||||
paddingTop: 30,
|
|
||||||
backgroundColor: hover && !makeFancy ? theme.palette.surfaceColor : "transparent",
|
backgroundColor: hover && !makeFancy ? theme.palette.surfaceColor : "transparent",
|
||||||
cursor: hover ? "pointer" : "default",
|
cursor: hover ? "pointer" : "default",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
@@ -59,6 +57,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
: "1px solid rgba(255,255,255,0.3)",
|
: "1px solid rgba(255,255,255,0.3)",
|
||||||
borderImage: makeFancy ? "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1" : "none",
|
borderImage: makeFancy ? "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1" : "none",
|
||||||
transition: 'all 0.2s ease-in-out',
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
paddingBottom: isCloud ? 0 : 175,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -256,26 +255,27 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
body: openApidata,
|
body: openApidata,
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
|
||||||
setValidation(false);
|
setValidation(false);
|
||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson.success) {
|
if (responseJson?.success === true) {
|
||||||
setAppValidation(responseJson.id);
|
setAppValidation(responseJson?.id)
|
||||||
} else {
|
navigate(`/apps/new?id=${responseJson?.id}`)
|
||||||
if (responseJson.reason !== undefined) {
|
} else {
|
||||||
setOpenApiError(responseJson.reason);
|
if (responseJson.reason !== undefined) {
|
||||||
}
|
setOpenApiError(responseJson.reason)
|
||||||
toast("An error occurred in the response");
|
}
|
||||||
}
|
toast("An error occurred in the response");
|
||||||
})
|
}
|
||||||
.catch((error) => {
|
})
|
||||||
setValidation(false);
|
.catch((error) => {
|
||||||
toast(error.toString());
|
setValidation(false);
|
||||||
setOpenApiError(error.toString());
|
toast(error.toString());
|
||||||
});
|
setOpenApiError(error.toString());
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirectOpenApi = () => {
|
const redirectOpenApi = () => {
|
||||||
@@ -345,23 +345,23 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
// Common dialog styles
|
// Common dialog styles
|
||||||
const dialogStyle = {
|
const dialogStyle = {
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.DialogStyle.border,
|
||||||
minWidth: '500px',
|
minWidth: '500px',
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
backgroundColor: "#1A1A1A",
|
backgroundColor: theme.palette.DialogStyle.backgroundColor,
|
||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
'& .MuiDialogContent-root': {
|
'& .MuiDialogContent-root': {
|
||||||
backgroundColor: "#1A1A1A",
|
backgroundColor: theme.palette.DialogStyle.backgroundColor,
|
||||||
padding: '24px',
|
padding: '24px',
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
},
|
},
|
||||||
'& .MuiDialogTitle-root': {
|
'& .MuiDialogTitle-root': {
|
||||||
backgroundColor: "#1A1A1A",
|
backgroundColor: theme.palette.DialogStyle.backgroundColor,
|
||||||
padding: '24px',
|
padding: '24px',
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
},
|
},
|
||||||
'& .MuiDialogActions-root': {
|
'& .MuiDialogActions-root': {
|
||||||
backgroundColor: "#1A1A1A",
|
backgroundColor: theme.palette.DialogStyle.backgroundColor,
|
||||||
padding: '16px 24px',
|
padding: '16px 24px',
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
},
|
},
|
||||||
@@ -396,7 +396,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
pl: 4,
|
pl: 4,
|
||||||
pr: 3,
|
pr: 3,
|
||||||
}}>
|
}}>
|
||||||
<Typography variant="h5" sx={{ fontWeight: 500, color: "#F1F1F1" }}>
|
<Typography variant="h5"color="textPrimary" sx={{ fontWeight: 500, }}>
|
||||||
Create New App
|
Create New App
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -408,15 +408,15 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
onClose()
|
onClose()
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: theme.palette.text.primary,
|
||||||
'&:hover': { bgcolor: 'rgba(255, 255, 255, 0.1)' }
|
'&:hover': { bgcolor: theme.palette.hoverColor },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent sx={{ p: 3 }}>
|
<DialogContent sx={{ p: 3 }}>
|
||||||
<div style={{ display: "flex", gap: '16px' }}>
|
<div style={{ display: "flex", gap: 16, }}>
|
||||||
<AppCreateButton
|
<AppCreateButton
|
||||||
text="Upload OpenAPI or Swagger"
|
text="Upload OpenAPI or Swagger"
|
||||||
func={() => {
|
func={() => {
|
||||||
@@ -476,7 +476,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
px: 4,
|
px: 4,
|
||||||
}}>
|
}}>
|
||||||
<Typography variant="h6" sx={{
|
<Typography variant="h6" sx={{
|
||||||
color: '#F1F1F1',
|
color: theme.palette.text.primary,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontFamily: theme?.typography?.fontFamily
|
fontFamily: theme?.typography?.fontFamily
|
||||||
}}>
|
}}>
|
||||||
@@ -501,7 +501,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent sx={{ px: 4, py: 3 }}>
|
<DialogContent sx={{ px: 4, py: 3 }}>
|
||||||
<div style={{ display: "flex", fontSize: '14px', gap: '5px', alignItems: 'center', marginBottom: '10px', fontFamily: theme?.typography?.fontFamily, marginTop: '15px' }}>
|
<div style={{ display: "flex", fontSize: '14px', gap: '5px', alignItems: 'center', marginBottom: '10px', fontFamily: theme?.typography?.fontFamily, marginTop: '15px' }}>
|
||||||
<Typography sx={{ color: 'rgba(255,255,255,0.85)', fontSize: '16px' }}>
|
<Typography sx={{ color: theme.palette.text.primary, fontSize: '16px' }}>
|
||||||
Paste in the URI for the OpenAPI or find out
|
Paste in the URI for the OpenAPI or find out
|
||||||
</Typography>
|
</Typography>
|
||||||
<Link style={{
|
<Link style={{
|
||||||
@@ -582,6 +582,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
py: 1,
|
py: 1,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
borderColor: '#FF8544',
|
borderColor: '#FF8544',
|
||||||
|
color: '#FF8544',
|
||||||
bgcolor: 'rgba(255,133,68,0.1)'
|
bgcolor: 'rgba(255,133,68,0.1)'
|
||||||
},
|
},
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
@@ -664,7 +665,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
px: 4,
|
px: 4,
|
||||||
}}>
|
}}>
|
||||||
<Typography variant="h6" sx={{
|
<Typography variant="h6" sx={{
|
||||||
color: '#F1F1F1',
|
color: theme.palette.text.primary,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
}}>
|
}}>
|
||||||
@@ -680,8 +681,8 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
setValidation(false)
|
setValidation(false)
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255,255,255,0.7)',
|
color: theme.palette.text.primary,
|
||||||
'&:hover': { bgcolor: 'rgba(255,255,255,0.1)' }
|
'&:hover': { bgcolor: theme.palette.hoverColor }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
@@ -689,7 +690,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent sx={{ px: 4, py: 3, pt: 0 }}>
|
<DialogContent sx={{ px: 4, py: 3, pt: 0 }}>
|
||||||
<Typography sx={{
|
<Typography sx={{
|
||||||
color: 'rgba(255,255,255,0.85)',
|
color: theme.palette.text.primary,
|
||||||
mb: 2,
|
mb: 2,
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
mt: 2,
|
mt: 2,
|
||||||
@@ -705,10 +706,10 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
placeholder="API Documentation URL"
|
placeholder="API Documentation URL"
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: theme.palette.platformColor,
|
bgcolor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
'& .MuiOutlinedInput-root': {
|
'& .MuiOutlinedInput-root': {
|
||||||
height: '40px',
|
height: '40px',
|
||||||
color: 'white',
|
color: theme.palette.text.primary,
|
||||||
'& fieldset': {
|
'& fieldset': {
|
||||||
borderWidth: '1px',
|
borderWidth: '1px',
|
||||||
borderImage: "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1",
|
borderImage: "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1",
|
||||||
@@ -756,7 +757,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
|
|||||||
{circularLoader}
|
{circularLoader}
|
||||||
{
|
{
|
||||||
!validation &&
|
!validation &&
|
||||||
<Typography sx={{ color: '#c5c5c5', fontSize: '14px', fontFamily: theme?.typography?.fontFamily, }}>
|
<Typography color="textSecondary" sx={{ fontSize: '14px', fontFamily: theme?.typography?.fontFamily, }}>
|
||||||
This may take multiple minutes based on the size of the documentation.
|
This may take multiple minutes based on the size of the documentation.
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export const findSpecificApp = (framework, inputcategory) => {
|
|||||||
id: "",
|
id: "",
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("findSpecificApp: unknown category: ", category)
|
//console.log("findSpecificApp: unknown category: ", category)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ import {
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
);
|
);
|
||||||
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { memo, useCallback, useEffect, useState, useContext } from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -25,12 +25,20 @@ import LaunchIcon from '@mui/icons-material/Launch';
|
|||||||
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
import { CloudDownloadOutlined, Delete } from '@mui/icons-material';
|
import { CloudDownloadOutlined, Delete } from '@mui/icons-material';
|
||||||
import { findSpecificApp } from '../components/AppFramework.jsx';
|
import { findSpecificApp } from '../components/AppFramework.jsx';
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import YAML from 'yaml';
|
import YAML from 'yaml';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { InstantSearch, connectHits, connectSearchBox } from 'react-instantsearch-dom';
|
||||||
|
import algoliasearch from "algoliasearch/lite";
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
|
||||||
const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
const searchClient = algoliasearch(
|
||||||
|
"JNSS5CFDZZ",
|
||||||
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
|
);;
|
||||||
|
|
||||||
|
const AppModal = ({ open, onClose, app, globalUrl, getApps}) => {
|
||||||
|
|
||||||
const [frameworkData, setFrameworkData] = useState({})
|
const [frameworkData, setFrameworkData] = useState({})
|
||||||
const [userdata, setUserdata] = useState({})
|
const [userdata, setUserdata] = useState({})
|
||||||
@@ -44,6 +52,9 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
const [deleteModalOpen, setDeleteModalOpen] = useState(false)
|
const [deleteModalOpen, setDeleteModalOpen] = useState(false)
|
||||||
const [sharingConfiguration, setSharingConfiguration] = React.useState("you");
|
const [sharingConfiguration, setSharingConfiguration] = React.useState("you");
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
const parseUsecase = (subcase) => {
|
const parseUsecase = (subcase) => {
|
||||||
const srcdata = findSpecificApp(frameworkData, subcase.type)
|
const srcdata = findSpecificApp(frameworkData, subcase.type)
|
||||||
const dstdata = findSpecificApp(frameworkData, subcase.last)
|
const dstdata = findSpecificApp(frameworkData, subcase.last)
|
||||||
@@ -79,8 +90,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
});
|
});
|
||||||
}, [app]);
|
}, [app]);
|
||||||
|
|
||||||
|
const getFramework = () => {
|
||||||
const getFramework = () => {
|
|
||||||
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -295,8 +305,6 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setUsecaseLoading(true)
|
setUsecaseLoading(true)
|
||||||
getAvailableWorkflows()
|
getAvailableWorkflows()
|
||||||
@@ -329,6 +337,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
//delete apps from local storage
|
//delete apps from local storage
|
||||||
localStorage.removeItem("apps");
|
localStorage.removeItem("apps");
|
||||||
getApps();
|
getApps();
|
||||||
|
onClose();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
toast("Failed deleting app. Does it still exist?");
|
toast("Failed deleting app. Does it still exist?");
|
||||||
@@ -511,12 +520,12 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
border: "1px solid #494949",
|
border: "1px solid #494949",
|
||||||
minWidth: '440px',
|
minWidth: '440px',
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
'& .MuiDialogContent-root': {
|
'& .MuiDialogContent-root': {
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.DialogStyle.backgroundColor,
|
||||||
},
|
},
|
||||||
'& .MuiDialogTitle-root': {
|
'& .MuiDialogTitle-root': {
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.DialogStyle.backgroundColor,
|
||||||
},
|
},
|
||||||
'& .MuiTypography-root': {
|
'& .MuiTypography-root': {
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
@@ -548,7 +557,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
<IconButton
|
<IconButton
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: theme.palette.textColor,
|
||||||
'&:hover': { bgcolor: 'rgba(255, 255, 255, 0.1)' }
|
'&:hover': { bgcolor: 'rgba(255, 255, 255, 0.1)' }
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -628,16 +637,14 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: '#494949',
|
|
||||||
'&:hover': { bgcolor: '#494949' },
|
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
minWidth: '45px',
|
minWidth: '45px',
|
||||||
width: '45px',
|
width: '45px',
|
||||||
height: '40px',
|
height: '40px',
|
||||||
padding: 2,
|
padding: 2,
|
||||||
color: "#fff",
|
|
||||||
fontFamily: theme?.typography?.fontFamily
|
fontFamily: theme?.typography?.fontFamily
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
@@ -653,19 +660,16 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
{(userdata?.id === app?.owner)? (
|
{(userdata?.id === app?.owner)? (
|
||||||
<Tooltip title={"Delete app (confirm box will show)"}>
|
<Tooltip title={"Delete app (confirm box will show)"}>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="contained"
|
||||||
component="label"
|
component="label"
|
||||||
color="primary"
|
color="secondary"
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: '#494949',
|
|
||||||
'&:hover': { bgcolor: '#494949', border: 'none' },
|
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
minWidth: '45px',
|
minWidth: '45px',
|
||||||
width: '45px',
|
width: '45px',
|
||||||
height: '40px',
|
height: '40px',
|
||||||
padding: 2,
|
padding: 2,
|
||||||
color: "#fff",
|
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
border: 'none'
|
border: 'none'
|
||||||
}}
|
}}
|
||||||
@@ -682,15 +686,13 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
{(canEditApp && app?.generated) && (
|
{(canEditApp && app?.generated) && (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: "#494949",
|
|
||||||
'&:hover': { bgcolor: '#494949' },
|
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
py: 1,
|
py: 1,
|
||||||
px: 3,
|
px: 3,
|
||||||
height: '40px',
|
height: '40px',
|
||||||
color: "#fff",
|
|
||||||
fontFamily: theme?.typography?.fontFamily
|
fontFamily: theme?.typography?.fontFamily
|
||||||
}}
|
}}
|
||||||
startIcon={canEditApp ? <EditIcon /> : <ForkRightIcon />}
|
startIcon={canEditApp ? <EditIcon /> : <ForkRightIcon />}
|
||||||
@@ -720,22 +722,11 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
textAlign: "start",
|
textAlign: "start",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}}>
|
}}>
|
||||||
<Typography
|
<WorkflowCard app={app}/>
|
||||||
variant="h6"
|
|
||||||
sx={{
|
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
|
||||||
fontSize: '24px',
|
|
||||||
fontWeight: 600,
|
|
||||||
mb: 0.3,
|
|
||||||
color: '#fff'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
20
|
|
||||||
</Typography>
|
|
||||||
<Typography
|
<Typography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: theme.palette.textColor,
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
fontSize: '14px'
|
fontSize: '14px'
|
||||||
}}
|
}}
|
||||||
@@ -746,7 +737,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
<div style={{
|
<div style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
textAlign: "start",
|
textAlign: "start",
|
||||||
borderLeft: "1px solid rgba(255, 255, 255, 0.12)",
|
borderLeft: theme.palette.defaultBorder,
|
||||||
paddingLeft: "10px",
|
paddingLeft: "10px",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
}}>
|
}}>
|
||||||
@@ -758,7 +749,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
}}>
|
}}>
|
||||||
{Array.isArray(app?.actions) ? app.actions.length : app?.actions}
|
{Array.isArray(app?.actions) ? app.actions.length : app?.actions}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)' }}>
|
<Typography variant="body2" sx={{ color: theme.palette.textColor }}>
|
||||||
Actions
|
Actions
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
@@ -768,14 +759,14 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
paddingLeft: "10px",
|
paddingLeft: "10px",
|
||||||
paddingTop: "5px"
|
paddingTop: "5px"
|
||||||
}}>
|
}}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '4px', marginBottom: "5px", fontFamily: theme?.typography?.fontFamily, fontSize: "14px", fontWeight: 600, color: 'white' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '4px', marginBottom: "5px", fontFamily: theme?.typography?.fontFamily, fontSize: "14px", fontWeight: 600, color: theme.palette.text.primary }}>
|
||||||
{
|
{
|
||||||
app?.collection ? (
|
app?.collection ? (
|
||||||
<>
|
<>
|
||||||
<CheckCircleIcon sx={{ color: '#4CAF50' }} />
|
<CheckCircleIcon sx={{ color: '#4CAF50' }} />
|
||||||
<Typography variant="body1" sx={{
|
<Typography variant="body1" sx={{
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
color: '#fff',
|
color: theme.palette.textColor,
|
||||||
marginTop: "1px",
|
marginTop: "1px",
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
fontSize: "16px"
|
fontSize: "16px"
|
||||||
@@ -789,7 +780,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
marginTop: "1px",
|
marginTop: "1px",
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: theme.palette.textColor,
|
||||||
fontFamily: theme?.typography?.fontFamily
|
fontFamily: theme?.typography?.fontFamily
|
||||||
}}>
|
}}>
|
||||||
No collection yet
|
No collection yet
|
||||||
@@ -838,7 +829,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
bgcolor: '#2F2F2F',
|
bgcolor: themeMode === "dark" ? "#1E1E1E" : "#F5F5F5",
|
||||||
p: 2,
|
p: 2,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -901,16 +892,14 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
<div style={{ display: "flex", justifyContent: "center", fontFamily: theme?.typography?.fontFamily }}>
|
<div style={{ display: "flex", justifyContent: "center", fontFamily: theme?.typography?.fontFamily }}>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: '#FF8544',
|
|
||||||
'&:hover': { bgcolor: '#FF8544' },
|
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
py: 1,
|
py: 1,
|
||||||
px: 7,
|
px: 7,
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
letterSpacing: "0.5px",
|
letterSpacing: "0.5px",
|
||||||
color: "black",
|
|
||||||
fontFamily: theme?.typography?.fontFamily,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
minWidth: '200px'
|
minWidth: '200px'
|
||||||
}}
|
}}
|
||||||
@@ -930,3 +919,55 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default AppModal;
|
export default AppModal;
|
||||||
|
|
||||||
|
|
||||||
|
const WorkflowCard = memo(({ app }) => {
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
const [relatedWorkflows, setRelatedWorkflows] = useState(0);
|
||||||
|
|
||||||
|
const WorkflowHits = ({ hits }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
setRelatedWorkflows(hits?.length || 0);
|
||||||
|
}, [hits]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomWorkflowHits = connectHits(WorkflowHits);
|
||||||
|
|
||||||
|
const SearchBox = ({ refine, currentRefinement }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
if (name.length > 0 && currentRefinement !== name) {
|
||||||
|
refine(name?.split(" ")[0]);
|
||||||
|
}
|
||||||
|
}, [name, refine, currentRefinement]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomSearchBox = connectSearchBox(SearchBox);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (app?.name && app.name.trim().length > 0 && name !== app.name) {
|
||||||
|
const formattedName = app.name
|
||||||
|
.charAt(0)
|
||||||
|
.toUpperCase() + app.name.substring(1)
|
||||||
|
.replaceAll("_", " ");
|
||||||
|
setName(formattedName);
|
||||||
|
}
|
||||||
|
}, [app?.name]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography variant="h4">
|
||||||
|
{name.length > 0 ? (
|
||||||
|
<InstantSearch key={name} searchClient={searchClient} indexName="workflows">
|
||||||
|
<CustomSearchBox defaultRefinement={name?.split(" ")[0]}/>
|
||||||
|
<CustomWorkflowHits />
|
||||||
|
{relatedWorkflows}
|
||||||
|
</InstantSearch>
|
||||||
|
) : (
|
||||||
|
relatedWorkflows
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
InputAdornment,
|
InputAdornment,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const Appsearch = props => {
|
const Appsearch = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp, placeholder,
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp, placeholder,
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect, useRef, useContext } from "react";
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { useNavigate, Link } from 'react-router-dom';
|
||||||
import { isMobile } from 'react-device-detect';
|
import { isMobile } from 'react-device-detect';
|
||||||
@@ -36,9 +36,12 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
|
||||||
const AppSearchButtons = (props) => {
|
const AppSearchButtons = (props) => {
|
||||||
const { userdata, globalUrl, appFramework, moreButton, finishedApps, appType, totalApps, index, onNodeSelect, setDiscoveryData, appName, AppImage, setDefaultSearch, discoveryData, checkLogin, setMissing, getAppFramework, } = props
|
const { userdata, globalUrl, appFramework, moreButton, finishedApps, appType, totalApps, index, onNodeSelect, setDiscoveryData, appName, AppImage, setDefaultSearch, discoveryData, checkLogin, setMissing, getAppFramework, } = props
|
||||||
|
const { themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
@@ -88,7 +91,7 @@ const AppSearchButtons = (props) => {
|
|||||||
|
|
||||||
const foundApp = findSpecificApp(appFramework, appType)
|
const foundApp = findSpecificApp(appFramework, appType)
|
||||||
if (foundApp === undefined || foundApp === null) {
|
if (foundApp === undefined || foundApp === null) {
|
||||||
console.log("AppSearchButtons: App not found in appFramework: " + appType)
|
//console.log("AppSearchButtons: App not found in appFramework: " + appType)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,13 +198,13 @@ const AppSearchButtons = (props) => {
|
|||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
border: "1px solid var(--Container-Stroke, #494949)",
|
border: "1px solid var(--Container-Stroke, #494949)",
|
||||||
background: "var(--Container, #212121)",
|
background: theme.palette.platformColor,
|
||||||
boxShadow: "8px 8px 32px 24px rgba(0, 0, 0, 0.16)",
|
boxShadow: "8px 8px 32px 24px rgba(0, 0, 0, 0.16)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<div style={{ display: "flex", textAlign: "center", textTransform: "capitalize" }}>
|
<div style={{ display: "flex", textAlign: "center", textTransform: "capitalize" }}>
|
||||||
<Typography style={{ padding: 16, color: "#FFFFFF", textTransform: "capitalize" }}> {discoveryData} </Typography>
|
<Typography color="textPrimary" style={{ padding: 16, textTransform: "capitalize" }}> {discoveryData} </Typography>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@@ -288,17 +291,17 @@ const AppSearchButtons = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div style={{
|
<div style={{
|
||||||
display: "flex", height: 70, border: isHover ? "1px solid #f85a3e" : "var(--Container, #212121)", borderRadius: 8, background: isHover ? "var(--Container, #212121)" : "var(--Container, #212121)",
|
display: "flex", height: 70, border: isHover ? "1px solid #f85a3e" : "var(--Container, #212121)", borderRadius: 4, background: isHover ? "var(--Container, #212121)" : "var(--Container, #212121)",
|
||||||
alignItems: "center", justifyContent: "center",
|
alignItems: "center", justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
color="secondary"
|
|
||||||
style={{
|
style={{
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
display: "grid"
|
display: "grid",
|
||||||
|
backgroundColor: themeMode === "dark" ? "#212121" : "#F5F5F5",
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
if (onNodeSelect !== undefined) {
|
if (onNodeSelect !== undefined) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
Chip,
|
Chip,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BarChart,
|
BarChart,
|
||||||
@@ -73,6 +74,8 @@ const inputdata = {
|
|||||||
|
|
||||||
const LineChartWrapper = ({keys, inputname, height, width}) => {
|
const LineChartWrapper = ({keys, inputname, height, width}) => {
|
||||||
const [hovered, setHovered] = useState("");
|
const [hovered, setHovered] = useState("");
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
//console.log("Date: ", new Date("2019-11-14T08:00:00.000Z"))
|
//console.log("Date: ", new Date("2019-11-14T08:00:00.000Z"))
|
||||||
//var inputdata = keys.data
|
//var inputdata = keys.data
|
||||||
@@ -166,6 +169,8 @@ const AppStats = (defaultprops) => {
|
|||||||
const [searches, setSearches] = useState([]);
|
const [searches, setSearches] = useState([]);
|
||||||
const [clickData, setClickData] = useState(undefined);
|
const [clickData, setClickData] = useState(undefined);
|
||||||
const [conversionData, setConversionData] = useState(undefined);
|
const [conversionData, setConversionData] = useState(undefined);
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const handleDataSetting = (inputdata, grouping) => {
|
const handleDataSetting = (inputdata, grouping) => {
|
||||||
var newlist = []
|
var newlist = []
|
||||||
@@ -292,7 +297,7 @@ const AppStats = (defaultprops) => {
|
|||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
padding: 40,
|
padding: 40,
|
||||||
margin: 5,
|
margin: 5,
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.surfaceColor,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Widget: ", widgetData)
|
console.log("Widget: ", widgetData)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon } from '@mui/icons-material';
|
import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon } from '@mui/icons-material';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
//import algoliasearch from 'algoliasearch/lite';
|
//import algoliasearch from 'algoliasearch/lite';
|
||||||
import algoliasearch from 'algoliasearch';
|
import algoliasearch from 'algoliasearch';
|
||||||
import { InstantSearch, connectSearchBox, connectHits } from 'react-instantsearch-dom';
|
import { InstantSearch, connectSearchBox, connectHits } from 'react-instantsearch-dom';
|
||||||
@@ -20,10 +20,11 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import aa from 'search-insights'
|
import aa from 'search-insights'
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const Appsearch = props => {
|
const Appsearch = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
||||||
|
const { themeMode } = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs
|
const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs
|
||||||
@@ -54,10 +55,10 @@ const Appsearch = props => {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
fullWidth
|
fullWidth
|
||||||
style={{backgroundColor: "#2F2F2F", borderRadius: borderRadius, width: "100%",}}
|
style={{backgroundColor: theme.palette.textFieldStyle.backgroundColor, borderRadius: borderRadius, width: "100%",}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style:{
|
style:{
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
height: 50,
|
height: 50,
|
||||||
},
|
},
|
||||||
@@ -93,7 +94,7 @@ const Appsearch = props => {
|
|||||||
<Grid container spacing={0} style={{border: "1px solid rgba(255,255,255,0.2)", maxHeight: 250, minHeight: 250, overflowY: "auto", overflowX: "hidden", }}>
|
<Grid container spacing={0} style={{border: "1px solid rgba(255,255,255,0.2)", maxHeight: 250, minHeight: 250, overflowY: "auto", overflowX: "hidden", }}>
|
||||||
{hits.map((data, index) => {
|
{hits.map((data, index) => {
|
||||||
const paperStyle = {
|
const paperStyle = {
|
||||||
backgroundColor: index === mouseHoverIndex ? "rgba(255,255,255,0.8)" : "#2F2F2F",
|
backgroundColor: index === mouseHoverIndex ? theme.palette.hoverColor : theme.palette.textFieldStyle.backgroundColor,
|
||||||
color: index === mouseHoverIndex ? theme.palette.inputColor : "rgba(255,255,255,0.8)",
|
color: index === mouseHoverIndex ? theme.palette.inputColor : "rgba(255,255,255,0.8)",
|
||||||
// border: newSelectedApp.objectID !== data.objectID ? `1px solid rgba(255,255,255,0.2)` : "2px solid #f86a3e",
|
// border: newSelectedApp.objectID !== data.objectID ? `1px solid rgba(255,255,255,0.2)` : "2px solid #f86a3e",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useContext, memo, useMemo } from 'react';
|
import React, { useState, useEffect, useContext, memo, useMemo } from 'react';
|
||||||
|
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
||||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'
|
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'
|
||||||
@@ -28,12 +28,20 @@ import {
|
|||||||
Paper,
|
Paper,
|
||||||
Chip,
|
Chip,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
|
Box,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BarChart,
|
BarChart,
|
||||||
|
BarSeries,
|
||||||
|
Bar,
|
||||||
|
BarLabel,
|
||||||
|
|
||||||
GridlineSeries,
|
GridlineSeries,
|
||||||
Gridline,
|
Gridline,
|
||||||
|
TooltipArea,
|
||||||
|
ChartTooltip,
|
||||||
|
TooltipTemplate,
|
||||||
} from 'reaviz';
|
} from 'reaviz';
|
||||||
|
|
||||||
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||||
@@ -42,31 +50,54 @@ import { Context } from '../context/ContextApi.jsx';
|
|||||||
const LineChartWrapper = ({keys, inputname, height, width}) => {
|
const LineChartWrapper = ({keys, inputname, height, width}) => {
|
||||||
const [hovered, setHovered] = useState("");
|
const [hovered, setHovered] = useState("");
|
||||||
const inputdata = keys.data === undefined ? keys : keys.data
|
const inputdata = keys.data === undefined ? keys : keys.data
|
||||||
|
const {themeMode} = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: "white", border: "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, padding: 30, marginTop: 15, backgroundColor: theme.palette.platformColor, overflow: "hidden", }}>
|
<div style={{color: "white", border: "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, padding: 30, marginTop: 15, backgroundColor: theme.palette.platformColor, overflow: "hidden", }}>
|
||||||
<Typography variant="h6" style={{marginBotton: 15, }}>
|
<Typography variant="h6" style={{marginBotton: 30, }}>
|
||||||
{inputname}
|
{inputname}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<BarChart
|
<BarChart
|
||||||
|
style={{marginTop: 100, }}
|
||||||
width={"100%"}
|
width={"100%"}
|
||||||
height={height}
|
height={height}
|
||||||
data={inputdata}
|
data={inputdata}
|
||||||
|
|
||||||
|
series={
|
||||||
|
<BarSeries
|
||||||
|
bar={
|
||||||
|
<Bar />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
gridlines={
|
gridlines={
|
||||||
<GridlineSeries line={<Gridline direction="all" />} />
|
<GridlineSeries line={<Gridline direction="all" />} />
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const AppStats = (defaultprops) => {
|
const AppStats = (defaultprops) => {
|
||||||
const { globalUrl, selectedOrganization, userdata, isCloud, inputWorkflows,clickedFromOrgTab } = defaultprops;
|
const {
|
||||||
|
globalUrl,
|
||||||
|
selectedOrganization,
|
||||||
|
userdata,
|
||||||
|
isCloud,
|
||||||
|
inputWorkflows,
|
||||||
|
clickedFromOrgTab,
|
||||||
|
syncStats,
|
||||||
|
} = defaultprops;
|
||||||
|
|
||||||
const [keys, setKeys] = useState([])
|
const [keys, setKeys] = useState([])
|
||||||
const [searches, setSearches] = useState([]);
|
const [searches, setSearches] = useState([]);
|
||||||
const [appRuns, setAppruns] = useState(undefined);
|
const [appRuns, setAppruns] = useState(undefined);
|
||||||
|
const [childOrgsAppRuns, setChildOrgsAppRuns] = useState(undefined);
|
||||||
const [appRunCosts, setApprunCosts] = useState(undefined);
|
const [appRunCosts, setApprunCosts] = useState(undefined);
|
||||||
const [workflowRuns, setWorkflowRuns] = useState(undefined);
|
const [workflowRuns, setWorkflowRuns] = useState(undefined);
|
||||||
const [subflowRuns, setSubflowRuns] = useState(undefined);
|
const [subflowRuns, setSubflowRuns] = useState(undefined);
|
||||||
@@ -83,6 +114,8 @@ const AppStats = (defaultprops) => {
|
|||||||
const [workflows, setWorkflows] = useState(inputWorkflows === undefined ? [] : inputWorkflows)
|
const [workflows, setWorkflows] = useState(inputWorkflows === undefined ? [] : inputWorkflows)
|
||||||
const [resultRows, setResultRows] = useState([])
|
const [resultRows, setResultRows] = useState([])
|
||||||
const [resultLoading, setResultLoading] = useState(true)
|
const [resultLoading, setResultLoading] = useState(true)
|
||||||
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor)
|
||||||
|
|
||||||
const includedExecutions = selectedOrganization?.sync_features?.app_executions !== undefined ? selectedOrganization?.sync_features?.app_executions?.limit : 0
|
const includedExecutions = selectedOrganization?.sync_features?.app_executions !== undefined ? selectedOrganization?.sync_features?.app_executions?.limit : 0
|
||||||
|
|
||||||
@@ -94,9 +127,6 @@ const AppStats = (defaultprops) => {
|
|||||||
|
|
||||||
|
|
||||||
const getWorkflowStats = async (workflow, startTime, endTime) => {
|
const getWorkflowStats = async (workflow, startTime, endTime) => {
|
||||||
if (!userdata.support) {
|
|
||||||
return workflow
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workflow.id === undefined || workflow.id === null || workflow.id === "") {
|
if (workflow.id === undefined || workflow.id === null || workflow.id === "") {
|
||||||
return workflow
|
return workflow
|
||||||
@@ -161,12 +191,8 @@ const AppStats = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadWorkflowStats = (foundWorkflows, startTime, endTime) => {
|
const loadWorkflowStats = (foundWorkflows, startTime, endTime) => {
|
||||||
if (!userdata.support) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundWorkflows === undefined || foundWorkflows === null || foundWorkflows.length === 0) {
|
if (foundWorkflows === undefined || foundWorkflows === null || foundWorkflows.length === 0) {
|
||||||
console.log("Not workflows")
|
setResultLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +201,9 @@ const AppStats = (defaultprops) => {
|
|||||||
const promises = foundWorkflows.slice(0, 50).map(wf => getWorkflowStats(wf, startTime, endTime));
|
const promises = foundWorkflows.slice(0, 50).map(wf => getWorkflowStats(wf, startTime, endTime));
|
||||||
|
|
||||||
const allData = Promise.all(promises);
|
const allData = Promise.all(promises);
|
||||||
|
if (allData === undefined || allData === null) {
|
||||||
|
setResultLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
allData.then((data) => {
|
allData.then((data) => {
|
||||||
var total = 0
|
var total = 0
|
||||||
@@ -234,15 +263,16 @@ const AppStats = (defaultprops) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statistics["daily_statistics"] === undefined || statistics["daily_statistics"] === null) {
|
const statKey = syncStats === true ? "onprem_stats" : "daily_statistics"
|
||||||
|
if (statistics[statKey] === undefined || statistics[statKey] === null) {
|
||||||
setFilteredStatistics(statistics)
|
setFilteredStatistics(statistics)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate month to date cost
|
// Calculate month to date cost
|
||||||
var mtd_cost = 0
|
var mtd_cost = 0
|
||||||
for (let key in statistics["daily_statistics"]) {
|
for (let key in statistics[statKey]) {
|
||||||
const item = statistics["daily_statistics"][key]
|
const item = statistics[statKey][key]
|
||||||
if (item["date"] === undefined) {
|
if (item["date"] === undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -300,8 +330,8 @@ const AppStats = (defaultprops) => {
|
|||||||
|
|
||||||
// Check if start time is before the daily statistics["date"] string
|
// Check if start time is before the daily statistics["date"] string
|
||||||
var newlist = []
|
var newlist = []
|
||||||
for (let key in statistics["daily_statistics"]) {
|
for (let key in statistics[statKey]) {
|
||||||
const item = statistics["daily_statistics"][key]
|
const item = statistics[statKey][key]
|
||||||
if (item["date"] === undefined) {
|
if (item["date"] === undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -332,7 +362,7 @@ const AppStats = (defaultprops) => {
|
|||||||
var appexecutions = 0
|
var appexecutions = 0
|
||||||
var estimatedcost = 0
|
var estimatedcost = 0
|
||||||
if (newlist.length > 0) {
|
if (newlist.length > 0) {
|
||||||
tmpstats["daily_statistics"] = newlist
|
tmpstats[statKey] = newlist
|
||||||
|
|
||||||
for (let key in newlist) {
|
for (let key in newlist) {
|
||||||
const item = newlist[key]
|
const item = newlist[key]
|
||||||
@@ -386,7 +416,8 @@ const AppStats = (defaultprops) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dailyStats = inputdata.daily_statistics
|
const statKey = syncStats === true ? "onprem_stats" : "daily_statistics"
|
||||||
|
const dailyStats = inputdata[statKey]
|
||||||
if (dailyStats === undefined || dailyStats === null) {
|
if (dailyStats === undefined || dailyStats === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -396,6 +427,11 @@ const AppStats = (defaultprops) => {
|
|||||||
"data": []
|
"data": []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var childorgappRuns = {
|
||||||
|
"key": "Child Org App Runs",
|
||||||
|
"data": []
|
||||||
|
}
|
||||||
|
|
||||||
var workflowRuns = {
|
var workflowRuns = {
|
||||||
"key": "Workflow Runs (includes subflows)",
|
"key": "Workflow Runs (includes subflows)",
|
||||||
"data": []
|
"data": []
|
||||||
@@ -437,6 +473,13 @@ const AppStats = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item["child_app_executions"] !== undefined && item["child_app_executions"] !== null) {
|
||||||
|
childorgappRuns["data"].push({
|
||||||
|
key: new Date(item["date"]),
|
||||||
|
data: inputdata["child_app_executions"]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Check if workflow_executions key in item
|
// Check if workflow_executions key in item
|
||||||
if (item["workflow_executions"] !== undefined && item["workflow_executions"] !== null) {
|
if (item["workflow_executions"] !== undefined && item["workflow_executions"] !== null) {
|
||||||
workflowRuns["data"].push({
|
workflowRuns["data"].push({
|
||||||
@@ -466,6 +509,15 @@ const AppStats = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputdata["daily_child_app_executions"] !== undefined && inputdata["daily_app_executions"] !== null) {
|
||||||
|
childorgappRuns["data"].push({
|
||||||
|
key: new Date(),
|
||||||
|
data: inputdata["daily_child_app_executions"]
|
||||||
|
})
|
||||||
|
|
||||||
|
//setApprunCosts(appcostRuns)
|
||||||
|
}
|
||||||
|
|
||||||
if (inputdata["daily_workflow_executions"] !== undefined && inputdata["daily_workflow_executions"] !== null) {
|
if (inputdata["daily_workflow_executions"] !== undefined && inputdata["daily_workflow_executions"] !== null) {
|
||||||
workflowRuns["data"].push({
|
workflowRuns["data"].push({
|
||||||
key: new Date(),
|
key: new Date(),
|
||||||
@@ -480,6 +532,11 @@ const AppStats = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for parent orgs
|
||||||
|
if (childorgappRuns["data"].length > 0) {
|
||||||
|
setChildOrgsAppRuns(childorgappRuns)
|
||||||
|
}
|
||||||
|
|
||||||
setSubflowRuns(subflowRuns)
|
setSubflowRuns(subflowRuns)
|
||||||
setWorkflowRuns(workflowRuns)
|
setWorkflowRuns(workflowRuns)
|
||||||
setAppruns(appRuns)
|
setAppruns(appRuns)
|
||||||
@@ -529,11 +586,14 @@ const AppStats = (defaultprops) => {
|
|||||||
|
|
||||||
const paperStyle = {
|
const paperStyle = {
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
padding: 40,
|
padding: "40px",
|
||||||
margin: 5,
|
margin: "5px",
|
||||||
backgroundColor: theme.palette.platformColor,
|
backgroundColor: theme.palette.cardBackgroundColor,
|
||||||
border: "1px solid rgba(255,255,255,0.3)",
|
border: theme.palette.defaultBorder,
|
||||||
maxWidth: 300,
|
maxWidth: "300px",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.cardHoverColor,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
@@ -646,85 +706,94 @@ const AppStats = (defaultprops) => {
|
|||||||
<div className="content" style={{width: "100%", margin: "auto", }}>
|
<div className="content" style={{width: "100%", margin: "auto", }}>
|
||||||
<Typography style={{margin: "auto", marginLeft: 10, marginBottom: 20, fontSize: 16}} color="textSecondary">
|
<Typography style={{margin: "auto", marginLeft: 10, marginBottom: 20, fontSize: 16}} color="textSecondary">
|
||||||
All shown statistics are gathered from <a
|
All shown statistics are gathered from <a
|
||||||
href={`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`}
|
href={`${globalUrl}/api/v1/orgs/${selectedOrganization?.id}/stats`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
style={{ textDecoration: "none", color: "#FF8444",}}
|
style={{ textDecoration: "none", color: theme.palette.linkColor,}}
|
||||||
>Your Organisation Statistics. </a>
|
>Your Organisation Statistics. </a>
|
||||||
It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
|
It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
|
||||||
|
|
||||||
|
<br style={{}}/>
|
||||||
|
{syncStats !== true ? null :
|
||||||
|
"PS: You are currently looking at data from your onprem synced org"}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<div style={{display: "flex", flexDirection: "column", textAlign: "center",}}>
|
<div style={{display: "flex", flexDirection: "column", textAlign: "center",}}>
|
||||||
<div style={{flexDirection: "row", }}>
|
<div style={{flexDirection: "row", }}>
|
||||||
{filteredStatistics !== undefined ?
|
{filteredStatistics !== undefined ?
|
||||||
<div style={{flex: 1, display: "flex", textAlign: "center",}}>
|
<div style={{flex: 1, display: "flex", textAlign: "center",}}>
|
||||||
<Tooltip title={
|
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
{syncStats == true ? null :
|
||||||
The cost of app runs in the selected period based on {filteredStatistics.monthly_app_executions} App Runs. These numbers do not exclude your included 10.000/month or {includedExecutions} App Runs per month. App Run cost: ${invocationCost}.
|
<Tooltip title={
|
||||||
</Typography>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
}>
|
The cost of app runs in the selected period based on {filteredStatistics.monthly_app_executions} App Runs. These numbers do not exclude your included 10.000/month or {includedExecutions} App Runs per month. App Run cost: ${invocationCost}.
|
||||||
<Paper style={paperStyle}>
|
|
||||||
<Typography variant="h4">
|
|
||||||
${selectedOrganization.lead_info.customer === false && selectedOrganization.lead_info.pov === false ?
|
|
||||||
0
|
|
||||||
:
|
|
||||||
apprunCost
|
|
||||||
}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
}>
|
||||||
Period Cost
|
<Box sx={paperStyle}>
|
||||||
</Typography>
|
<Typography variant="h4">
|
||||||
</Paper>
|
${selectedOrganization?.lead_info?.customer === false && selectedOrganization?.lead_info?.pov === false ?
|
||||||
</Tooltip>
|
0
|
||||||
|
:
|
||||||
|
apprunCost
|
||||||
|
}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="h6">
|
||||||
|
Period Cost
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
|
{syncStats === true ? null :
|
||||||
<Tooltip title={
|
<Tooltip title={
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
App runs in the selected period
|
App runs in the selected period
|
||||||
</Typography>
|
</Typography>
|
||||||
}>
|
}>
|
||||||
<Paper style={paperStyle}>
|
<Box sx={paperStyle}>
|
||||||
<Typography variant="h4">
|
<Typography variant="h4">
|
||||||
{filteredStatistics.monthly_app_executions === null || filteredStatistics.monthly_app_executions === undefined ? 0 : filteredStatistics.monthly_app_executions}
|
{filteredStatistics.monthly_app_executions === null || filteredStatistics.monthly_app_executions === undefined ? 0 : filteredStatistics.monthly_app_executions}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
App Runs
|
App Runs
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
|
{syncStats === true ? null :
|
||||||
<Tooltip title={
|
<Tooltip title={
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
Workflow runs in the selected period
|
Workflow runs in the selected period
|
||||||
</Typography>
|
</Typography>
|
||||||
}>
|
}>
|
||||||
<Paper style={paperStyle}>
|
<Box sx={paperStyle}>
|
||||||
<Typography variant="h4">
|
<Typography variant="h4">
|
||||||
{filteredStatistics.monthly_workflow_executions === null || filteredStatistics.monthly_workflow_executions === undefined ? 0 : filteredStatistics.monthly_workflow_executions}
|
{filteredStatistics.monthly_workflow_executions === null || filteredStatistics.monthly_workflow_executions === undefined ? 0 : filteredStatistics.monthly_workflow_executions}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
Workflow Runs
|
Workflow Runs
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={
|
}
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
|
||||||
Estimated cost to be billed at the end of the current month. Subtracted contractually included app runs. Actual cost month to date: ${monthToDateCost}. App Run cost: ${invocationCost}.
|
{syncStats === true ? null :
|
||||||
</Typography>
|
<Tooltip title={
|
||||||
}>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
<Paper style={{
|
Estimated cost to be billed at the end of the current month. Subtracted contractually included app runs. Actual cost month to date: ${monthToDateCost}. App Run cost: ${invocationCost}.
|
||||||
textAlign: "center",
|
|
||||||
padding: 40,
|
|
||||||
margin: 5,
|
|
||||||
marginLeft: clickedFromOrgTab? null:90,
|
|
||||||
backgroundColor: theme.palette.platformColor,
|
|
||||||
border: "1px solid rgba(255,255,255,0.3)",
|
|
||||||
maxWidth: 300,
|
|
||||||
}}>
|
|
||||||
<Typography variant="h4">
|
|
||||||
${monthTotalCost}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
}>
|
||||||
Estimated cost
|
<Box sx={paperStyle}>
|
||||||
</Typography>
|
<Typography variant="h4">
|
||||||
</Paper>
|
${monthTotalCost}
|
||||||
</Tooltip>
|
</Typography>
|
||||||
|
<Typography variant="h6">
|
||||||
|
Estimated cost
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
@@ -895,7 +964,13 @@ const AppStats = (defaultprops) => {
|
|||||||
{appRuns === undefined ?
|
{appRuns === undefined ?
|
||||||
null
|
null
|
||||||
:
|
:
|
||||||
<LineChartWrapper keys={appRuns} height={300} width={"100%"} inputname={"Daily App Runs"}/>
|
<LineChartWrapper keys={appRuns} height={300} width={"100%"} inputname={"App Runs - Current Org"}/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{childOrgsAppRuns === undefined ?
|
||||||
|
null
|
||||||
|
:
|
||||||
|
<LineChartWrapper keys={childOrgsAppRuns} height={300} width={"100%"} inputname={"Child Org App Runs"}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
{workflowRuns === undefined ?
|
{workflowRuns === undefined ?
|
||||||
@@ -916,56 +991,58 @@ const AppStats = (defaultprops) => {
|
|||||||
<LineChartWrapper keys={appRunCosts} height={300} width={"100%"} inputname={"Apprun cost - Cost per day"}/>
|
<LineChartWrapper keys={appRunCosts} height={300} width={"100%"} inputname={"Apprun cost - Cost per day"}/>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
|
{syncStats === true ? null :
|
||||||
|
<div style={{height: 150+resultRows.length * 25, padding: "10px 0px 10px 0px", }}>
|
||||||
|
{resultLoading ?
|
||||||
|
<div style={{margin: "auto", alignItems: "center", width: 350, height: "100%", }}>
|
||||||
|
<Typography variant="body2" color="textSecondary" component="p" style={{textAlign: "center", marginTop: 50, marginBottom: 15, }}>
|
||||||
|
Loading usage for selected period (may take a while)
|
||||||
|
|
||||||
<div style={{height: 150+resultRows.length * 25, padding: "10px 0px 10px 0px", }}>
|
<CircularProgress style={{marginTop: 15, }} />
|
||||||
{resultLoading ?
|
</Typography>
|
||||||
<div style={{margin: "auto", alignItems: "center", width: 350, height: "100%", }}>
|
</div>
|
||||||
<Typography variant="body2" color="textSecondary" component="p" style={{textAlign: "center", marginTop: 50, marginBottom: 15, }}>
|
:
|
||||||
Loading usage for selected period (may take a while)
|
<DataGrid
|
||||||
</Typography>
|
rows={resultRows}
|
||||||
<CircularProgress style={{}} />
|
columns={columns}
|
||||||
</div>
|
pageSize={100}
|
||||||
:
|
rowsPerPageOptions={[10, 20, 50, 100]}
|
||||||
<DataGrid
|
checkboxSelection
|
||||||
rows={resultRows}
|
disableSelectionOnClick
|
||||||
columns={columns}
|
onPageSizeChange={(newPageSize) => {
|
||||||
pageSize={100}
|
//setRowsPerPage(newPageSize)
|
||||||
rowsPerPageOptions={[10, 20, 50, 100]}
|
//submitSearch(workflowId, status, startTime, endTime, rowCursor, newPageSize)
|
||||||
checkboxSelection
|
}}
|
||||||
disableSelectionOnClick
|
// event for when clicking next page
|
||||||
onPageSizeChange={(newPageSize) => {
|
// Hide page changer
|
||||||
//setRowsPerPage(newPageSize)
|
onPageChange={(params) => {
|
||||||
//submitSearch(workflowId, status, startTime, endTime, rowCursor, newPageSize)
|
console.log("page params: ", params)
|
||||||
}}
|
}}
|
||||||
// event for when clicking next page
|
onSelectionModelChange={(newSelection) => {
|
||||||
// Hide page changer
|
console.log("newSelection: ", newSelection)
|
||||||
onPageChange={(params) => {
|
//console.log("newSelection: ", newSelection)
|
||||||
console.log("page params: ", params)
|
//setSelectedWorkflowExecutionsIndexes(newSelection)
|
||||||
}}
|
//var found = []
|
||||||
onSelectionModelChange={(newSelection) => {
|
//for (var i = 0; i < newSelection.length; i++) {
|
||||||
console.log("newSelection: ", newSelection)
|
// // Find the workflow in the resultRows
|
||||||
//console.log("newSelection: ", newSelection)
|
// var selected = resultRows.find((workflow) => {
|
||||||
//setSelectedWorkflowExecutionsIndexes(newSelection)
|
// return workflow.id === newSelection[i]
|
||||||
//var found = []
|
// })
|
||||||
//for (var i = 0; i < newSelection.length; i++) {
|
|
||||||
// // Find the workflow in the resultRows
|
|
||||||
// var selected = resultRows.find((workflow) => {
|
|
||||||
// return workflow.id === newSelection[i]
|
|
||||||
// })
|
|
||||||
|
|
||||||
// if (selected === undefined || selected === null) {
|
// if (selected === undefined || selected === null) {
|
||||||
// continue
|
// continue
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// found.push(selected)
|
// found.push(selected)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//setSelectedWorkflowExecutions(found)
|
//setSelectedWorkflowExecutions(found)
|
||||||
}}
|
}}
|
||||||
// Track which items are selected
|
// Track which items are selected
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React, { useState, useEffect, useContext } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import { ToastContainer, toast } from "react-toastify"
|
import { ToastContainer, toast } from "react-toastify"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CheckCircle as CheckCircleIcon,
|
CheckCircle as CheckCircleIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
@@ -13,8 +12,11 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
Button,
|
Button,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Grid,
|
ToggleButtonGroup,
|
||||||
Card,
|
ToggleButton,
|
||||||
|
useMediaQuery,
|
||||||
|
TextField,
|
||||||
|
Box,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -27,18 +29,98 @@ import { Context } from "../context/ContextApi.jsx";
|
|||||||
|
|
||||||
const Branding = (props) => {
|
const Branding = (props) => {
|
||||||
const { globalUrl, userdata, serverside, billingInfo,clickedFromOrgTab, stripeKey, selectedOrganization, handleGetOrg, } = props;
|
const { globalUrl, userdata, serverside, billingInfo,clickedFromOrgTab, stripeKey, selectedOrganization, handleGetOrg, } = props;
|
||||||
|
const { themeMode, handleThemeChange, supportEmail, setSupportEmail, logoutUrl, setLogoutUrl, brandColor, setBrandColor, setBrandName } = useContext(Context)
|
||||||
//const alert = useAlert();
|
//const alert = useAlert();
|
||||||
const [publishingInfo, setPublishingInfo] = useState("");
|
const [publishingInfo, setPublishingInfo] = useState("");
|
||||||
const [publishRequirements, setPublishRequirements] = useState([])
|
const [publishRequirements, setPublishRequirements] = useState([])
|
||||||
|
const [currentSelectedTheme, setCurrentSelectedTheme] = useState(themeMode);
|
||||||
|
const [integrationPartner, setIntegrationPartner] = useState(false);
|
||||||
|
const [changingTheme, setChangingTheme] = useState(false);
|
||||||
|
const theme = getTheme(themeMode, brandColor)
|
||||||
|
const [selectedBrandColor, setSelectedBrandColor] = useState(theme?.palette?.main || "#FF8544")
|
||||||
|
const [selectedBrandName, setSelectedBrandName] = useState(selectedOrganization?.branding?.brand_name || "")
|
||||||
|
|
||||||
const { leftSideBarOpenByClick } = useContext(Context)
|
const [isLoading,setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleEditOrg = (joinStatus) => {
|
const handleEditOrg = (joinStatus) => {
|
||||||
|
setIsLoading(true)
|
||||||
const data = {
|
const data = {
|
||||||
"org_id": selectedOrganization.id,
|
"org_id": selectedOrganization.id,
|
||||||
"creator_config": joinStatus,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (joinStatus === "join" || joinStatus === "leave") {
|
||||||
|
data["creator_config"] = joinStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "light" || joinStatus === "dark" || joinStatus === "system") {
|
||||||
|
data["branding"] = {
|
||||||
|
"theme": joinStatus,
|
||||||
|
"enable_chat": selectedOrganization?.branding?.enable_chat || false,
|
||||||
|
"home_url": selectedOrganization?.branding?.home_url || "",
|
||||||
|
"brand_color": selectedOrganization?.branding?.brand_color || theme.palette.primary.main,
|
||||||
|
"brand_name": selectedOrganization?.branding?.brand_name || "",
|
||||||
|
"logout_url": selectedOrganization?.branding?.logout_url || "",
|
||||||
|
"support_email": selectedOrganization?.branding?.support_email || "",
|
||||||
|
}
|
||||||
|
|
||||||
|
data["editing_branding"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "brand_color") {
|
||||||
|
data["branding"] = {
|
||||||
|
"theme": selectedOrganization?.branding?.theme || "dark",
|
||||||
|
"enable_chat": selectedOrganization?.branding?.enable_chat || false,
|
||||||
|
"home_url": selectedOrganization?.branding?.home_url || "",
|
||||||
|
"brand_color": selectedBrandColor,
|
||||||
|
"brand_name": selectedOrganization?.branding?.brand_name || "",
|
||||||
|
"logout_url": selectedOrganization?.branding?.logout_url || "",
|
||||||
|
"support_email": selectedOrganization?.branding?.support_email || "",
|
||||||
|
}
|
||||||
|
|
||||||
|
data["editing_branding"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "brand_name") {
|
||||||
|
data["branding"] = {
|
||||||
|
"theme": selectedOrganization?.branding?.theme || "dark",
|
||||||
|
"enable_chat": selectedOrganization?.branding?.enable_chat || false,
|
||||||
|
"home_url": selectedOrganization?.branding?.home_url || "",
|
||||||
|
"brand_color": selectedOrganization?.branding?.brand_color || theme.palette.primary.main,
|
||||||
|
"brand_name": selectedBrandName,
|
||||||
|
"logout_url": selectedOrganization?.branding?.logout_url || "",
|
||||||
|
"support_email": selectedOrganization?.branding?.support_email || "",
|
||||||
|
}
|
||||||
|
toast.info("Updating brand name to " + selectedBrandName + ". Please wait a moment.")
|
||||||
|
data["editing_branding"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "support_email") {
|
||||||
|
data["branding"] = {
|
||||||
|
"theme": selectedOrganization?.branding?.theme || "dark",
|
||||||
|
"enable_chat": selectedOrganization?.branding?.enable_chat || false,
|
||||||
|
"home_url": selectedOrganization?.branding?.home_url || "",
|
||||||
|
"brand_color": selectedOrganization?.branding?.brand_color || theme.palette.primary.main,
|
||||||
|
"brand_name": selectedOrganization?.branding?.brand_name || "",
|
||||||
|
"support_email": supportEmail,
|
||||||
|
"logout_url": selectedOrganization?.branding?.logout_url || "",
|
||||||
|
}
|
||||||
|
data["editing_branding"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "logout_url") {
|
||||||
|
data["branding"] = {
|
||||||
|
"theme": selectedOrganization?.branding?.theme || "dark",
|
||||||
|
"enable_chat": selectedOrganization?.branding?.enable_chat || false,
|
||||||
|
"home_url": selectedOrganization?.branding?.home_url || "",
|
||||||
|
"brand_color": selectedOrganization?.branding?.brand_color || theme.palette.primary.main,
|
||||||
|
"brand_name": selectedOrganization?.branding?.brand_name || "",
|
||||||
|
"support_email": selectedOrganization?.branding?.support_email || "",
|
||||||
|
"logout_url": logoutUrl,
|
||||||
|
}
|
||||||
|
data["editing_branding"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
|
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
mode: "cors",
|
mode: "cors",
|
||||||
@@ -56,20 +138,65 @@ const Branding = (props) => {
|
|||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
toast("Failed updating org: ", responseJson.reason);
|
toast("Failed updating org: ", responseJson.reason);
|
||||||
} else {
|
} else {
|
||||||
if (joinStatus == "join") {
|
if (joinStatus === "join" || joinStatus === "leave") {
|
||||||
setPublishingInfo("Your organization is now part of the Partner Program. You can now create, publish and manage content for your organization's public page.")
|
if (joinStatus === "join") {
|
||||||
} else {
|
setPublishingInfo("Your organization is now part of the Partner Program. You can now create, publish and manage content for your organization's public page.")
|
||||||
setPublishingInfo("Your organization is no longer part of the Creator Incentive Program. You can still create a creator account to manage your organization's content.")
|
} else {
|
||||||
|
setPublishingInfo("Your organization is no longer part of the Creator Incentive Program. You can still create a creator account to manage your organization's content.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "light" || joinStatus === "dark" || joinStatus === "system") {
|
||||||
|
handleThemeChange(joinStatus)
|
||||||
|
setChangingTheme(false)
|
||||||
|
setCurrentSelectedTheme(joinStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "support_email") {
|
||||||
|
toast.info("Support email updated successfully.")
|
||||||
|
if (supportEmail?.length > 0) {
|
||||||
|
setSupportEmail(supportEmail)
|
||||||
|
}else {
|
||||||
|
setSupportEmail("support@shuffler.io")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "logout_url") {
|
||||||
|
toast.info("Logout URL updated successfully.")
|
||||||
|
setLogoutUrl(logoutUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "brand_color") {
|
||||||
|
toast.info("Brand color updated successfully.")
|
||||||
|
setBrandColor(selectedBrandColor)
|
||||||
|
localStorage.setItem("brandColor", selectedBrandColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinStatus === "brand_name") {
|
||||||
|
toast.info("Brand name updated successfully.")
|
||||||
|
setBrandName(selectedBrandName)
|
||||||
|
localStorage.setItem("brandName", selectedBrandName)
|
||||||
|
}
|
||||||
|
|
||||||
handleGetOrg(selectedOrganization.id);
|
handleGetOrg(selectedOrganization.id);
|
||||||
}
|
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast("Err: " + error.toString());
|
toast("Err: " + error.toString());
|
||||||
});
|
setIsLoading(false)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userdata && userdata?.active_org && userdata?.active_org?.branding?.theme?.length > 0) {
|
||||||
|
console.log("Setting current selected theme from userdata", userdata?.active_org?.branding?.theme);
|
||||||
|
setCurrentSelectedTheme(userdata?.active_org?.branding?.theme);
|
||||||
|
}
|
||||||
|
},[userdata]);
|
||||||
|
|
||||||
// Should enable / disable org branding
|
// Should enable / disable org branding
|
||||||
const handleChangePublishing = () => {
|
const handleChangePublishing = () => {
|
||||||
console.log("Handle change publishing");
|
console.log("Handle change publishing");
|
||||||
@@ -118,15 +245,55 @@ const Branding = (props) => {
|
|||||||
const isPartner = leadinfo.includes("partner")
|
const isPartner = leadinfo.includes("partner")
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedOrganization?.branding?.theme && selectedOrganization?.creator_org?.length === 0) {
|
||||||
|
setCurrentSelectedTheme(selectedOrganization.branding.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedOrganization?.creator_org?.length > 0 && userdata?.active_org?.branding.theme) {
|
||||||
|
setCurrentSelectedTheme(userdata?.active_org?.branding.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
selectedOrganization &&
|
||||||
|
selectedOrganization?.branding?.brand_color &&
|
||||||
|
selectedOrganization?.branding?.brand_color !== selectedBrandColor
|
||||||
|
) {
|
||||||
|
setSelectedBrandColor(selectedOrganization.branding.brand_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedOrganization?.branding?.brand_name && selectedOrganization?.branding?.brand_name !== selectedBrandName) {
|
||||||
|
setSelectedBrandName(selectedOrganization.branding.brand_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [selectedOrganization, userdata]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if ((userdata && userdata?.org_status?.includes("integration_partner") && !integrationPartner && !userdata?.org_status?.includes("sub_org")) || userdata?.support) {
|
||||||
|
setIntegrationPartner(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
},[userdata, integrationPartner]);
|
||||||
|
|
||||||
|
const handleColorChange = (e) => {
|
||||||
|
setSelectedBrandColor(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveColorChanges = () => {
|
||||||
|
toast.info("Updating brand color to " + selectedBrandColor + ". Please wait a moment.")
|
||||||
|
handleEditOrg("brand_color");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: clickedFromOrgTab? "100%": "auto", height: "100%", minHeight: 1100, boxSizing: 'border-box', transition: "width 0.3s ease", padding: "27px 10px 19px 27px", height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
|
<div style={{ width: clickedFromOrgTab? "100%": "auto", height: "100%", minHeight: 1100, boxSizing: 'border-box', transition: "width 0.3s ease", padding: "27px 10px 19px 27px", backgroundColor: theme.palette.platformColor, borderRadius: '16px', scrollbarWidth: "thin", scrollbarColor: theme.palette.scrollbarColorTransparent, }}>
|
||||||
<div style={{height: 843, overflowY: "auto",}}>
|
<div style={{ overflowY: "auto",}}>
|
||||||
<div style={{width: "100%", overflowX: 'hidden', }}>
|
<div style={{width: "100%", overflowX: 'hidden', }}>
|
||||||
<Typography style={{fontSize: 24, fontWeight: "bold", marginTop: clickedFromOrgTab ?0:null,}}>
|
<Typography style={{fontSize: 24, fontWeight: "bold", marginTop: clickedFromOrgTab ?0:null,}}>
|
||||||
Partner Status & Branding
|
Partner Status & Branding
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10, marginBottom: 10, fontSize: 16 }}>
|
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10, marginBottom: 10, fontSize: 16 }}>
|
||||||
You can customize your organization's branding by uploading a logo, changing the color scheme and a lot more.
|
Please note that same theme settings are applied to all sub organizations for partners.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography variant="body1" color="textSecondary" style={{display: 'flex', marginTop: 20, marginBottom: 10 }}>
|
<Typography variant="body1" color="textSecondary" style={{display: 'flex', marginTop: 20, marginBottom: 10 }}>
|
||||||
@@ -150,7 +317,8 @@ const Branding = (props) => {
|
|||||||
style={{ textDecoration: "none" }} // Optional: remove underline
|
style={{ textDecoration: "none" }} // Optional: remove underline
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
style={{
|
style={{
|
||||||
marginTop: 20,
|
marginTop: 20,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
@@ -176,15 +344,15 @@ const Branding = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Divider style={{marginTop: 50, marginBottom: 50, }} />
|
<Divider style={{marginTop: 50, marginBottom: 50, color: theme.palette.defaultBorder}} />
|
||||||
<Typography style={{fontSize: 24, fontWeight: "bold"}}>
|
<Typography style={{fontSize: 24, fontWeight: "bold"}}>
|
||||||
Partner Program
|
Public Partner Program
|
||||||
</Typography>
|
</Typography>
|
||||||
<div style={{ display: "flex", width: 900, marginTop: 10}}>
|
<div style={{ display: "flex", width: 900, marginTop: 10}}>
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
<Typography variant="body1" color="textSecondary" style={{fontSize: 16}}>
|
<Typography variant="body2" color="textSecondary">
|
||||||
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization IS reversible.<div/>Support: <a href="mailto:support@shuffler.io"target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>support@shuffler.io</a>
|
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: theme.palette.linkColor}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: theme.palette.linkColor}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization IS reversible.<div/>Support: <a href={`mailto:${supportEmail}`} target="_blank" style={{ textDecoration: "none", color: theme.palette.linkColor}}>{supportEmail}</a>
|
||||||
</Typography>
|
</Typography>
|
||||||
{selectedOrganization.creator_id == "" ?
|
{selectedOrganization.creator_id == "" ?
|
||||||
<Typography variant="h6" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
<Typography variant="h6" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
||||||
@@ -195,7 +363,9 @@ const Branding = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style={{ height: 40, marginTop: 10, width: 300, textTransform: 'none', fontSize: 18, backgroundColor: "#ff8544", color: "#1a1a1a" }}
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
style={{ height: 40, marginTop: 10, width: 300, textTransform: 'none', fontSize: 18, }}
|
||||||
variant={selectedOrganization.creator_id == "" ? "contained" : "outlined"}
|
variant={selectedOrganization.creator_id == "" ? "contained" : "outlined"}
|
||||||
color={selectedOrganization.creator_id == "" ? "primary" : "secondary"}
|
color={selectedOrganization.creator_id == "" ? "primary" : "secondary"}
|
||||||
disabled={!isOrganizationReady()}
|
disabled={!isOrganizationReady()}
|
||||||
@@ -222,6 +392,257 @@ const Branding = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{integrationPartner ? (
|
||||||
|
<>
|
||||||
|
<Divider style={{marginTop: 50, marginBottom: 50, color: theme.palette.defaultBorder}} />
|
||||||
|
<Typography style={{fontSize: 24, fontWeight: "bold"}}>
|
||||||
|
Parent & Sub Organization Branding
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10, marginBottom: 10, fontSize: 16 }}>
|
||||||
|
Sub organizations are not allowed to change their branding. The branding is inherited from the parent organization.
|
||||||
|
</Typography>
|
||||||
|
<ToggleButtonGroup
|
||||||
|
value={currentSelectedTheme}
|
||||||
|
exclusive
|
||||||
|
disabled={isLoading}
|
||||||
|
onChange={(event, newTheme) => {
|
||||||
|
if (newTheme === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newTheme === currentSelectedTheme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (changingTheme === true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setChangingTheme(true)
|
||||||
|
handleEditOrg(newTheme);
|
||||||
|
}}
|
||||||
|
aria-label="theme"
|
||||||
|
style={{ justifyContent: "flex-start", marginBottom: 10, marginTop: 20 }}
|
||||||
|
>
|
||||||
|
<ToggleButton value="light" aria-label="light theme" style={{ backgroundColor: currentSelectedTheme === "light" ? theme.palette.hoverColor : theme.palette.backgroundColor }}>
|
||||||
|
Light
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton value="dark" aria-label="dark theme" style={{ backgroundColor: currentSelectedTheme === "dark" ? theme.palette.hoverColor : theme.palette.backgroundColor }}>
|
||||||
|
Dark
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton value="system" aria-label="system theme" style={{ backgroundColor: currentSelectedTheme === "system" ? theme.palette.hoverColor : theme.palette.backgroundColor }}>
|
||||||
|
System
|
||||||
|
</ToggleButton>
|
||||||
|
</ToggleButtonGroup>
|
||||||
|
</>
|
||||||
|
): null}
|
||||||
|
|
||||||
|
{integrationPartner ? <>
|
||||||
|
<Divider style={{marginTop: 50, marginBottom: 50, color: theme.palette.defaultBorder}} />
|
||||||
|
<Typography variant="text" style={{color: theme.palette.text.primary, fontFamily: theme.typography.fontFamily,}}>Brand Name</Typography>
|
||||||
|
<div style={{ display: "flex", alignItems: 'center', justifyContent: 'flex-start', marginBottom: 10, gap: 15, maxWidth: 434 }}>
|
||||||
|
<TextField
|
||||||
|
type="text"
|
||||||
|
id="brandName"
|
||||||
|
value={selectedBrandName}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setSelectedBrandName(value);
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
PaperProps={{ style: { backgroundColor: theme.palette.backgroundColor, borderRadius: 4, border: `1px solid ${theme.palette.defaultBorder}` } }}
|
||||||
|
style={{
|
||||||
|
height: 36,
|
||||||
|
borderRadius: 4,
|
||||||
|
border: `1px solid ${theme.palette.defaultBorder}`,
|
||||||
|
width: 300
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={()=>{
|
||||||
|
if (selectedBrandName !== selectedOrganization.branding.brandName) {
|
||||||
|
handleEditOrg("brand_name");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={isLoading}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 110, height: 35 }}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>: null}
|
||||||
|
|
||||||
|
{integrationPartner ? <>
|
||||||
|
<Typography variant="text" style={{color: theme.palette.text.primary, fontFamily: theme.typography.fontFamily}}>Brand Color</Typography>
|
||||||
|
<div style={{ display: "flex", alignItems: 'center', justifyContent: 'flex-start', marginBottom: 10, gap: 15, maxWidth: 434 }}>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
id="color"
|
||||||
|
name="color"
|
||||||
|
value={selectedBrandColor}
|
||||||
|
onChange={handleColorChange}
|
||||||
|
style={{
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
minWidth: 50,
|
||||||
|
minHeight: 50,
|
||||||
|
cursor: "pointer",
|
||||||
|
borderRadius: 5,
|
||||||
|
border: "none"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="text"
|
||||||
|
id="colorCode"
|
||||||
|
value={selectedBrandColor}
|
||||||
|
size="small"
|
||||||
|
fullWidth={true}
|
||||||
|
PaperProps={{ style: { backgroundColor: theme.palette.backgroundColor, borderRadius: 4, border: `1px solid ${theme.palette.defaultBorder}` } }}
|
||||||
|
style={{
|
||||||
|
height: 36,
|
||||||
|
padding: "0 10px",
|
||||||
|
borderRadius: 4,
|
||||||
|
border: `1px solid ${theme.palette.defaultBorder}`,
|
||||||
|
width: 260
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={()=>{saveColorChanges();}}
|
||||||
|
disabled={isLoading}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 110, height: 35 }}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>: null}
|
||||||
|
|
||||||
|
|
||||||
|
{integrationPartner ? (
|
||||||
|
<div style={{ width: "100%", maxWidth: 434, marginRight: 10, marginTop: 20 }}>
|
||||||
|
<Typography variant="text" style={{color: theme.palette.text.primary, fontFamily: theme.typography.fontFamily}}>Support Email</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
height: 35,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 434,
|
||||||
|
fontFamily: theme.typography.fontFamily,
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="Support Email"
|
||||||
|
type="email"
|
||||||
|
id="standard-required"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
value={supportEmail}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSupportEmail(e.target.value)
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: "35px",
|
||||||
|
fontSize: "1em",
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 110, height: 35 }}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
disabled={isLoading}
|
||||||
|
onClick={() => {
|
||||||
|
toast.info("Updating support email..")
|
||||||
|
handleEditOrg("support_email")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{integrationPartner ? (
|
||||||
|
<div style={{ width: "100%", maxWidth: 434, marginRight: 10, marginTop: 20 }}>
|
||||||
|
<Typography variant="text" style={{color: theme.palette.text.primary, fontFamily: theme.typography.fontFamily}}>Logout URL</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
height: 35,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 434,
|
||||||
|
fontFamily: theme.typography.fontFamily,
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="Logout URL"
|
||||||
|
type="text"
|
||||||
|
id="standard-required"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
value={logoutUrl}
|
||||||
|
onChange={(e) => {
|
||||||
|
setLogoutUrl(e.target.value)
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: "35px",
|
||||||
|
fontSize: "1em",
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 110, height: 35 }}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
disabled={isLoading}
|
||||||
|
onClick={() => {
|
||||||
|
toast.info("Updating logout url..")
|
||||||
|
handleEditOrg("logout_url")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,846 @@
|
|||||||
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
|
|
||||||
|
import { useParams, useNavigate, Link } from "react-router-dom";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import theme from '../theme.jsx';
|
||||||
|
import Markdown from 'react-markdown'
|
||||||
|
import { isMobile } from "react-device-detect";
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
|
||||||
|
import AppSearch from "../components/AppSearch1.jsx";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Divider,
|
||||||
|
ButtonGroup,
|
||||||
|
TextField,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
Typography,
|
||||||
|
CircularProgress,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Send as SendIcon,
|
||||||
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
|
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
||||||
|
import AuthenticationWindow from "../components/AuthenticationWindow.jsx";
|
||||||
|
|
||||||
|
const ChatBot = (props) => {
|
||||||
|
const { globalUrl } = props
|
||||||
|
const { supportEmail } = useContext(Context)
|
||||||
|
const [messages, setMessages] = useState([])
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [appAuthentication, setAppAuthentication] = React.useState([]);
|
||||||
|
const [inputAuth, setInputAuth] = useState([])
|
||||||
|
const [forceReauthentication, setForceReauthentication] = useState(false);
|
||||||
|
const [selectedType, setSelectedType] = useState("atomic");
|
||||||
|
|
||||||
|
const [appname, setAppname] = useState("");
|
||||||
|
const [threadId, setThreadId] = useState("");
|
||||||
|
const [runId, setRunId] = useState("");
|
||||||
|
|
||||||
|
const [showAppSearch, setShowAppSearch] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
const waitingMsg = "Processing..."
|
||||||
|
const viewWidth = isMobile ? "92%" : 800
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Check if loading and remove Waiting... from messages
|
||||||
|
const newmessages = messages
|
||||||
|
const foundmessages = messages.filter((msg) => msg.message !== waitingMsg)
|
||||||
|
if (foundmessages.length < newmessages.length) {
|
||||||
|
setMessages(foundmessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait 0.5 second
|
||||||
|
const objDiv = document.getElementById("messages-window");
|
||||||
|
if (objDiv !== undefined && objDiv !== null) {
|
||||||
|
setTimeout(() => {
|
||||||
|
objDiv.scrollTop = objDiv.scrollHeight;
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (appname === undefined || appname === null || appname === "") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the last message that was sent by us and reuse the same message content
|
||||||
|
// with added app stuff only
|
||||||
|
for (var i = messages.length-1; i >= 0; i--) {
|
||||||
|
const msg = messages[i]
|
||||||
|
if (msg.status === "sent") {
|
||||||
|
handleSubmit(undefined, msg.message)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [appname])
|
||||||
|
|
||||||
|
window.title = "Shuffle - New Chat"
|
||||||
|
let navigate = useNavigate();
|
||||||
|
|
||||||
|
// Automatic submit handler based on a lot of stuff :)
|
||||||
|
const handleSubmit = (e, inputmsg) => {
|
||||||
|
if (e !== undefined) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
|
setMessage("");
|
||||||
|
|
||||||
|
const sentId = uuidv4();
|
||||||
|
var parsedData = {
|
||||||
|
"query": inputmsg,
|
||||||
|
"thread_id": threadId,
|
||||||
|
"run_id": runId,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appname !== undefined && appname !== null && appname !== "") {
|
||||||
|
parsedData["app_name"] = appname
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputAuth !== undefined && inputAuth.length > 0) {
|
||||||
|
// Forcing first auth app to be used in request
|
||||||
|
try {
|
||||||
|
parsedData["app_name"] = inputAuth[0].name
|
||||||
|
parsedData["app_id"] = inputAuth[0].id
|
||||||
|
parsedData["category"] = inputAuth[0].category
|
||||||
|
parsedData["action_name"] = inputAuth[0].action_name
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
parsedData["app_name"] = inputAuth.apps[0].name
|
||||||
|
parsedData["app_id"] = inputAuth.apps[0].id
|
||||||
|
parsedData["category"] = inputAuth.apps[0].category
|
||||||
|
parsedData["action_name"] = inputAuth.apps[0].action_name
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedType !== "default") {
|
||||||
|
if (selectedType == "workflow") {
|
||||||
|
parsedData["output_format"] = "workflow_suggestion"
|
||||||
|
} else {
|
||||||
|
parsedData["output_format"] = selectedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("INPUT: ", parsedData)
|
||||||
|
|
||||||
|
setInputAuth([])
|
||||||
|
|
||||||
|
var newmessages = messages;
|
||||||
|
newmessages.push({
|
||||||
|
"id": sentId,
|
||||||
|
"status": "sent",
|
||||||
|
"message": inputmsg,
|
||||||
|
})
|
||||||
|
newmessages.push({
|
||||||
|
"id": sentId,
|
||||||
|
"status": "received",
|
||||||
|
"message": waitingMsg,
|
||||||
|
})
|
||||||
|
|
||||||
|
setMessages(newmessages);
|
||||||
|
|
||||||
|
//fetch(`http://localhost:8080/api/v1/conversation`, {
|
||||||
|
fetch(`${globalUrl}/api/v1/conversation`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify(parsedData),
|
||||||
|
})
|
||||||
|
.then((res) => res.text())
|
||||||
|
.then((resText) => {
|
||||||
|
setLoading(false)
|
||||||
|
var data = {}
|
||||||
|
|
||||||
|
// JSON parse
|
||||||
|
try {
|
||||||
|
data = JSON.parse(resText);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error parsing response as JSON: ", e);
|
||||||
|
|
||||||
|
newmessages = newmessages.filter((msg) => msg.message !== waitingMsg);
|
||||||
|
newmessages.push({
|
||||||
|
"status": "received",
|
||||||
|
"message": resText,
|
||||||
|
"id": uuidv4(),
|
||||||
|
});
|
||||||
|
|
||||||
|
setMessages(newmessages);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (data.run_id !== undefined && data.run_id !== null && data.run_id !== "") {
|
||||||
|
setRunId(data.run_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.thread_id !== undefined && data.thread_id !== null && data.thread_id !== "") {
|
||||||
|
setThreadId(data.thread_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.success === undefined) {
|
||||||
|
newmessages = newmessages.filter((msg) => msg.message !== waitingMsg);
|
||||||
|
newmessages.push({
|
||||||
|
"status": "received",
|
||||||
|
"message": resText,
|
||||||
|
"id": uuidv4(),
|
||||||
|
});
|
||||||
|
|
||||||
|
setMessages(newmessages);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// authentication for app
|
||||||
|
// app validation (choose one)
|
||||||
|
const defaultMessage = `Default output. The feature you're interacting with may not have been implemented yet. Contact ${supportEmail} with a screenshot of this and your input please.`
|
||||||
|
|
||||||
|
var outputmessage = defaultMessage;
|
||||||
|
var status = "received";
|
||||||
|
var action = ""
|
||||||
|
if (data.success === false) {
|
||||||
|
if (data.reason !== undefined) {
|
||||||
|
outputmessage = data.reason
|
||||||
|
}
|
||||||
|
|
||||||
|
status = "error"
|
||||||
|
} else {
|
||||||
|
if (data.reason !== undefined) {
|
||||||
|
outputmessage = data.reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action !== undefined) {
|
||||||
|
//console.log("Action is defined: ", data.action);
|
||||||
|
action = data.action
|
||||||
|
|
||||||
|
if (data.action === "app_authentication") {
|
||||||
|
// If success & app auth -> say auth success and show available labels
|
||||||
|
// If !success & app auth -> do authentication
|
||||||
|
if (data.success === true) {
|
||||||
|
newmessages = newmessages.filter((msg) => msg.message !== waitingMsg);
|
||||||
|
// No action for this.
|
||||||
|
// "action": action,
|
||||||
|
var appname = ""
|
||||||
|
if (data.apps !== undefined && data.apps !== null && data.apps.length > 0) {
|
||||||
|
appname = data.apps[0].name.replaceAll("_", " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputmessage = `**Please specify which ${appname} action you want to use**: \n`
|
||||||
|
if (data.available_labels !== undefined && data.available_labels !== null && data.available_labels.length > 0) {
|
||||||
|
for (var i = 0; i < data.available_labels.length; i++) {
|
||||||
|
outputmessage += "* " + data.available_labels[i] + "\n"
|
||||||
|
}
|
||||||
|
outputmessage += "* Reauthenticate ([see auth](/admin?tab=app_auth))"
|
||||||
|
}
|
||||||
|
//Some opavailable actions: " + data.apps.map((app) => app.name).join(", ")
|
||||||
|
const parsedmessage = {
|
||||||
|
"status": status,
|
||||||
|
"message": outputmessage,
|
||||||
|
"id": uuidv4(),
|
||||||
|
"category": data.category,
|
||||||
|
|
||||||
|
"thread_id": data.thread_id,
|
||||||
|
"run_id": data.run_id,
|
||||||
|
}
|
||||||
|
newmessages.push(parsedmessage);
|
||||||
|
setMessages(newmessages);
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (data.apps !== undefined) {
|
||||||
|
setInputAuth(data.apps)
|
||||||
|
|
||||||
|
setMessage(inputmsg);
|
||||||
|
|
||||||
|
setForceReauthentication(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (data.action === "select_category" || data.action === "select_app") {
|
||||||
|
console.log("[DEBUG] APP SELECTION! Should help them choose an app to use")
|
||||||
|
// Show a search field
|
||||||
|
setShowAppSearch(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newmessages = newmessages.filter((msg) => msg.message !== waitingMsg);
|
||||||
|
const parsedmessage = {
|
||||||
|
"status": status,
|
||||||
|
"message": outputmessage,
|
||||||
|
"id": uuidv4(),
|
||||||
|
"action": action,
|
||||||
|
"category": data.category,
|
||||||
|
|
||||||
|
"thread_id": data.thread_id,
|
||||||
|
"run_id": data.run_id,
|
||||||
|
}
|
||||||
|
newmessages.push(parsedmessage);
|
||||||
|
setMessages(newmessages);
|
||||||
|
console.log("New message: ", parsedmessage)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setLoading(false)
|
||||||
|
console.log("Problem: ", err);
|
||||||
|
|
||||||
|
setMessage(message);
|
||||||
|
newmessages = newmessages.filter((msg) => msg.message !== waitingMsg);
|
||||||
|
|
||||||
|
// Find the message with the sentId and change the status to error
|
||||||
|
newmessages.push({
|
||||||
|
"status": "error",
|
||||||
|
"message": message,
|
||||||
|
"error_message": "Failed to send: "+err,
|
||||||
|
"id": sentId,
|
||||||
|
});
|
||||||
|
setMessages(newmessages);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used to verify if the user is logged in after auth is done
|
||||||
|
const getAppAuthentication = () => {
|
||||||
|
console.log("Continue chat from the previous stage!");
|
||||||
|
|
||||||
|
fetch(globalUrl + "/api/v1/apps/authentication", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Status not 200 for app auth :O!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
if (!responseJson.success) {
|
||||||
|
console.log("Failed to get app auth!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newauth = [];
|
||||||
|
for (let authkey in responseJson.data) {
|
||||||
|
if (responseJson.data[authkey].defined === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newauth.push(responseJson.data[authkey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newauth.length > appAuthentication.length) {
|
||||||
|
console.log("New auth is longer than old auth. Set new auth!");
|
||||||
|
|
||||||
|
setForceReauthentication(false)
|
||||||
|
|
||||||
|
// Check if last message contains "reauth"
|
||||||
|
if (messages.length > 0) {
|
||||||
|
const lastmessage = messages[messages.length-1];
|
||||||
|
if (lastmessage.message.toLowerCase().includes("re-auth")) {
|
||||||
|
console.log("Skipping resend due to reauth")
|
||||||
|
|
||||||
|
var newmessages = messages
|
||||||
|
newmessages.push({
|
||||||
|
"status": "received",
|
||||||
|
"message": "Authentication done. What do you want to do?",
|
||||||
|
"id": uuidv4(),
|
||||||
|
});
|
||||||
|
setMessages(newmessages);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
handleSubmit(undefined, message)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleSubmit(undefined, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppAuthentication(newauth)
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("Error in getAppAuthentication: ", err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const AuthWrapper = (props) => {
|
||||||
|
const { app } = props;
|
||||||
|
const [authenticationModalOpen, setAuthenticationModalOpen] = React.useState(false);
|
||||||
|
|
||||||
|
console.log("AUTH: ", app)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{position: "absolute", right: 250, bottom: 150, }}>
|
||||||
|
{app.authentication.type === "oauth2" || app.authentication.type === "oauth2-app" ?
|
||||||
|
<AuthenticationOauth2
|
||||||
|
selectedApp={app}
|
||||||
|
selectedAction={{
|
||||||
|
"app_name": app.name,
|
||||||
|
"app_id": app.id,
|
||||||
|
"app_version": app.version,
|
||||||
|
"large_image": app.large_image,
|
||||||
|
}}
|
||||||
|
authenticationType={app.authentication}
|
||||||
|
isCloud={true}
|
||||||
|
authButtonOnly={true}
|
||||||
|
getAppAuthentication={getAppAuthentication}
|
||||||
|
/>
|
||||||
|
:
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
variant="contained"
|
||||||
|
style={{
|
||||||
|
marginBottom: 20,
|
||||||
|
marginTop: 20,
|
||||||
|
flex: 1,
|
||||||
|
textTransform: "none",
|
||||||
|
textAlign: "left",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
color: "#2f2f2f",
|
||||||
|
borderRadius: theme.palette?.borderRadius,
|
||||||
|
minWidth: 300,
|
||||||
|
maxWidth: 300,
|
||||||
|
maxHeight: 50,
|
||||||
|
overflow: "hidden",
|
||||||
|
border: `1px solid ${theme.palette.inputColor}`,
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
fullWidth
|
||||||
|
color="primary"
|
||||||
|
onClick={(e) => {
|
||||||
|
console.log("Click? ")
|
||||||
|
e.preventDefault();
|
||||||
|
setAuthenticationModalOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{display: "flex"}}>
|
||||||
|
<img
|
||||||
|
alt={app.name}
|
||||||
|
style={{ margin: 4, minHeight: 30, maxHeight: 30, borderRadius: theme.palette?.borderRadius, }}
|
||||||
|
src={app.large_image}
|
||||||
|
/>
|
||||||
|
<Typography style={{ margin: 0, marginLeft: 10, marginTop: 5,}} variant="body1">
|
||||||
|
Authenticate
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
|
||||||
|
{app.authentication.type !== "oauth2" && authenticationModalOpen ?
|
||||||
|
<AuthenticationWindow
|
||||||
|
selectedApp={app}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
getAppAuthentication={getAppAuthentication}
|
||||||
|
appAuthentication={appAuthentication}
|
||||||
|
authenticationModalOpen={authenticationModalOpen}
|
||||||
|
setAuthenticationModalOpen={setAuthenticationModalOpen}
|
||||||
|
/>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var amountfinished = 0;
|
||||||
|
const showAuthentication = inputAuth.map((app, index) => {
|
||||||
|
const authexists = appAuthentication.find((auth) => auth.app.id === app.id);
|
||||||
|
if (authexists !== undefined && forceReauthentication === false) {
|
||||||
|
console.log("Auth exists: ", authexists);
|
||||||
|
amountfinished += 1
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={index}>
|
||||||
|
<AuthWrapper app={app} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (amountfinished === inputAuth.length && amountfinished > 0) {
|
||||||
|
|
||||||
|
setInputAuth([])
|
||||||
|
setAppAuthentication([])
|
||||||
|
}
|
||||||
|
|
||||||
|
const showSamples =
|
||||||
|
<div style={{marginLeft: 10, marginRight: 10, }}>
|
||||||
|
<Card style={{backgroundColor: theme.palette.surfaceColor, borderRadius: theme.palette?.borderRadius,}}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6">
|
||||||
|
How many incidents did we get last week?
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card style={{backgroundColor: theme.palette.surfaceColor, borderRadius: theme.palette?.borderRadius, marginTop: 10, }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6">
|
||||||
|
Answer the last email from Jim about the new project, and say we're on it
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card style={{backgroundColor: theme.palette.surfaceColor, borderRadius: theme.palette?.borderRadius, marginTop: 10, }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6">
|
||||||
|
Is the IP 1.2.3.4 blocked? If not, block it.
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
function OuterLink(props) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
href={props.href}
|
||||||
|
style={{ color: "#f85a3e", textDecoration: "none" }}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Img(props) {
|
||||||
|
return <img style={{ borderRadius: theme.palette?.borderRadius, width: 750, maxWidth: "100%", marginTop: 15, marginBottom: 15, }} alt={props.alt} src={props.src} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CodeHandler(props) {
|
||||||
|
//console.log("Codehandler PROPS: ", props)
|
||||||
|
|
||||||
|
const propvalue = props.value !== undefined && props.value !== null ? props.value : props.children !== undefined && props.children !== null && props.children.length > 0 ? props.children[0] : ""
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
minWidth: "50%",
|
||||||
|
maxWidth: "100%",
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
overflowY: "auto",
|
||||||
|
|
||||||
|
// Check if props.inline === true, then do it inline
|
||||||
|
padding: props.inline ? 0 : 15,
|
||||||
|
display: props.inline ? "inline" : "block",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<code
|
||||||
|
style={{
|
||||||
|
// Wrap if larger than X
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
overflow: "auto",
|
||||||
|
}}
|
||||||
|
>{propvalue}</code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const markdownStyle = {
|
||||||
|
color: "rgba(255, 255, 255, 0.65)",
|
||||||
|
overflow: "hidden",
|
||||||
|
paddingBottom: 100,
|
||||||
|
margin: "auto",
|
||||||
|
maxWidth: "100%",
|
||||||
|
minWidth: "100%",
|
||||||
|
overflow: "hidden",
|
||||||
|
fontSize: isMobile ? "1.3rem" : "1.0rem",
|
||||||
|
}
|
||||||
|
|
||||||
|
const Heading = (props) => {
|
||||||
|
const element = React.createElement(
|
||||||
|
`h${props.level}`,
|
||||||
|
{ style: { marginTop: props.level === 1 ? 20 : 50 } },
|
||||||
|
props.children
|
||||||
|
);
|
||||||
|
const [hover, setHover] = useState(false);
|
||||||
|
|
||||||
|
var extraInfo = "";
|
||||||
|
return (
|
||||||
|
<Typography
|
||||||
|
onMouseOver={() => {
|
||||||
|
setHover(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.level !== 1 ? (
|
||||||
|
<Divider
|
||||||
|
style={{
|
||||||
|
width: "90%",
|
||||||
|
marginTop: 40,
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{element}
|
||||||
|
{/*hover ? <LinkIcon onMouseOver={() => {setHover(true)}} style={{cursor: "pointer", display: "inline", }} onClick={() => {
|
||||||
|
window.location.href += "#hello"
|
||||||
|
console.log(window.location)
|
||||||
|
//window.history.pushState('page2', 'Title', '/page2.php');
|
||||||
|
//window.history.replaceState('page2', 'Title', '/page2.php');
|
||||||
|
}} />
|
||||||
|
: ""
|
||||||
|
*/}
|
||||||
|
{extraInfo}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderedList = (props) => {
|
||||||
|
var parsedchildren = []
|
||||||
|
for (var i = 0; i < props.children.length; i++) {
|
||||||
|
const child = props.children[i]
|
||||||
|
if (child === "\n") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.props !== undefined && child.props.children !== undefined) {
|
||||||
|
// Remove <p> from the child wrapper
|
||||||
|
var parsedchild = []
|
||||||
|
for (var j = 0; j < child.props.children.length; j++) {
|
||||||
|
const childchild = child.props.children[j]
|
||||||
|
// print the raw childchild bytes, not string
|
||||||
|
if (childchild === "\n") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the childchild has <p> around it, remove it
|
||||||
|
parsedchild.push(childchild)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Not doing this as it breaks links
|
||||||
|
if (childchild.props !== undefined && childchild.props.children !== undefined) {
|
||||||
|
parsedchild.push(childchild.props.children)
|
||||||
|
} else {
|
||||||
|
parsedchild.push(childchild)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedchildren.push(parsedchild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ol style={{marginTop: 0, }}>
|
||||||
|
{parsedchildren.map((child, index) => {
|
||||||
|
return (
|
||||||
|
<li key={index} style={{minHeight: 0, display: "block", }}>
|
||||||
|
<p style={{marginTop: 0, marginBottom: 10, }}>
|
||||||
|
{index+1}. {child}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ol>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Paragraph = (props) => {
|
||||||
|
return (
|
||||||
|
<p style={{marginTop: 15, marginBottom: 15, }}>
|
||||||
|
{props.children}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const markdownComponents = {
|
||||||
|
ol: OrderedList,
|
||||||
|
ul: OrderedList,
|
||||||
|
img: Img,
|
||||||
|
code: CodeHandler,
|
||||||
|
h1: Heading,
|
||||||
|
h2: Heading,
|
||||||
|
h3: Heading,
|
||||||
|
h4: Heading,
|
||||||
|
h5: Heading,
|
||||||
|
h6: Heading,
|
||||||
|
a: OuterLink,
|
||||||
|
p: Paragraph,
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatWindow =
|
||||||
|
<div style={{minWidth: viewWidth, maxWidth: viewWidth, margin: "auto", textAlign: "left", minHeight: 1500, }}>
|
||||||
|
{messages.length === 0 ?
|
||||||
|
<span>
|
||||||
|
<h1>Shuffle AI</h1>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{showSamples}
|
||||||
|
</span>
|
||||||
|
: null}
|
||||||
|
<div
|
||||||
|
id="messages-window"
|
||||||
|
style={{
|
||||||
|
marginTop: 50,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
minHeight: 1500,
|
||||||
|
maxHeight: isMobile ? "85%" : "85%",
|
||||||
|
overflow: "auto", paddingBottom: 200,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{messages.map((message, index) => {
|
||||||
|
const float = message.status === "sent" ? "left" : "right";
|
||||||
|
const border = message.status === "error" ? "red" : "rgba(255,255,255,0.3)"
|
||||||
|
|
||||||
|
const hasAction = message.action !== undefined && message.action !== null && message.action !== ""
|
||||||
|
|
||||||
|
return (
|
||||||
|
// Make a chat bubble component
|
||||||
|
<div key={index} style={{position: "relative", width: "100%", marginTop: 15, marginLeft: isMobile ? 10 : 0, }}>
|
||||||
|
<Typography variant="body1" style={{display: "flex", backgroundColor: theme.palette.surfaceColor, color: "white", padding: "0px 10px 0px 10px", borderRadius: theme.palette?.borderRadius, float: float, border: `1px solid ${border}`, "cursor": hasAction ? "pointer" : "default", maxWidth: viewWidth-30, overflowWrap: "break-word", whiteSpace: "pre-line" }} onClick={() => {
|
||||||
|
if (!hasAction) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.action === "login") {
|
||||||
|
navigate("/login?view=/conversation&message=You must log in to use ShuffleGPT")
|
||||||
|
} else if (message.action === "app_authentication") {
|
||||||
|
console.log("App auth action!")
|
||||||
|
//setAuthenticationModalOpen(true)
|
||||||
|
} else {
|
||||||
|
console.log("\n\nUnknown click action: ", message.action)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{message.message === waitingMsg ? <CircularProgress style={{height: 20, width: 20, marginTop: 20, marginRight: 10, }} /> : null}
|
||||||
|
<span>
|
||||||
|
<Markdown
|
||||||
|
components={markdownComponents}
|
||||||
|
id="markdown_wrapper"
|
||||||
|
style={{
|
||||||
|
minHeight: 20,
|
||||||
|
marginTop: 0,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{message.message}
|
||||||
|
</Markdown>
|
||||||
|
|
||||||
|
{message.thread_id !== undefined && message.thread_id !== null && message.thread_id !== "" ?
|
||||||
|
<Typography variant="body2" style={{color: "rgba(255,255,255,0.5)", marginTop: 5, }}>
|
||||||
|
Thread: {message.thread_id}
|
||||||
|
</Typography>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{message.status === "error" && message.error_message ?
|
||||||
|
<Typography variant="body2" style={{color: "red", }}>
|
||||||
|
{message.error_message}
|
||||||
|
</Typography>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{(message.action === "select_category" || message.action === "select_app") && showAppSearch && index === messages.length-1 ?
|
||||||
|
<div style={{position: "absolute", right: 0, bottom: -100, }}>
|
||||||
|
<AppSearch
|
||||||
|
placeholder={"Find your "+message.category+" app"}
|
||||||
|
setNewSelectedApp={setAppname}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{showAuthentication}
|
||||||
|
|
||||||
|
<div style={{position: "fixed", bottom: 0, left: 0, width: "100%", zIndex: 100, backgroundColor: theme.palette.platformColor, }}>
|
||||||
|
<div style={{width: viewWidth, margin: "auto", }}>
|
||||||
|
{messages.length === 0 ?
|
||||||
|
<span>
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
Query Type
|
||||||
|
</Typography>
|
||||||
|
<ButtonGroup
|
||||||
|
fullWidth
|
||||||
|
color="secondary"
|
||||||
|
style={{display: "flex", marginTop: 10, }}
|
||||||
|
>
|
||||||
|
{/*
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
disabled
|
||||||
|
variant={selectedType === "default" ? "contained" : "outlined"}
|
||||||
|
onClick={() => setSelectedType("default")}
|
||||||
|
>
|
||||||
|
Auto
|
||||||
|
</Button>
|
||||||
|
*/}
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
variant={selectedType === "atomic" ? "contained" : "outlined"}
|
||||||
|
onClick={() => setSelectedType("atomic")}
|
||||||
|
>
|
||||||
|
Auto-run action
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
variant={selectedType === "support" ? "contained" : "outlined"}
|
||||||
|
onClick={() => setSelectedType("support")}
|
||||||
|
>
|
||||||
|
Support
|
||||||
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</span>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
<form onSubmit={(e) => handleSubmit(e, message)} style={{bottom: 20, marginTop: 10, marginBottom: isMobile ? 0 : 10, maxWidth: viewWidth, minWidth: viewWidth, }}>
|
||||||
|
<TextField
|
||||||
|
id="message"
|
||||||
|
fullWidth
|
||||||
|
disabled={loading}
|
||||||
|
label="Send a message"
|
||||||
|
value={message}
|
||||||
|
onChange={(e) => setMessage(e.target.value)}
|
||||||
|
variant="outlined"
|
||||||
|
autoFocus
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<IconButton
|
||||||
|
aria-label="send message"
|
||||||
|
onClick={(e) => handleSubmit(e, message)}
|
||||||
|
>
|
||||||
|
<SendIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
{isMobile ? null :
|
||||||
|
<Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 0,}} >
|
||||||
|
{`The Shuffle AI is a test system for automatic workflow generation and atomic functions for the future of Shuffle. Shuffle AI may use your organization info in the query, and attempts to auto-correct any failed behavior. If you have any questions, please contact us at ${supportEmail}`}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{width: isMobile ? "100%" : 1000, margin: "auto", paddingTop: 50, }}>
|
||||||
|
{chatWindow}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChatBot;
|
||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
Visibility as VisibilityIcon,
|
Visibility as VisibilityIcon,
|
||||||
VisibilityOff as VisibilityOffIcon,
|
VisibilityOff as VisibilityOffIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import theme from "../theme.jsx";
|
import { getTheme } from "../theme.jsx";
|
||||||
import { styled } from '@mui/styles';
|
import { styled } from '@mui/styles';
|
||||||
import { Context } from "../context/ContextApi.jsx";
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
|
||||||
@@ -48,13 +48,21 @@ const CloudSyncTab = (props) => {
|
|||||||
const [, forceUpdate] = React.useState();
|
const [, forceUpdate] = React.useState();
|
||||||
const itemColor = "white";
|
const itemColor = "white";
|
||||||
const isCloud = window?.location?.host === "localhost:3002" || window?.location?.host === "shuffler.io";
|
const isCloud = window?.location?.host === "localhost:3002" || window?.location?.host === "shuffler.io";
|
||||||
|
|
||||||
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
useEffect(() => { getSettings(); }, []);
|
useEffect(() => { getSettings(); }, []);
|
||||||
|
|
||||||
const GridItem = (props) => {
|
const GridItem = (props) => {
|
||||||
const [expanded, setExpanded] = React.useState(false);
|
const [expanded, setExpanded] = React.useState(false);
|
||||||
const [showEdit, setShowEdit] = React.useState(false);
|
const [showEdit, setShowEdit] = React.useState(false);
|
||||||
const [newValue, setNewValue] = React.useState(-100);
|
const [newValue, setNewValue] = React.useState(-100);
|
||||||
|
|
||||||
const primary = props.data.primary;
|
var primary = props.data.primary
|
||||||
|
|
||||||
|
const shownName = props.data.newname !== undefined && props.data.newname !== null && props.data.newname !== primary ? props.data.newname : primary
|
||||||
|
|
||||||
const secondary = props.data.secondary;
|
const secondary = props.data.secondary;
|
||||||
const primaryIcon = props.data.icon;
|
const primaryIcon = props.data.icon;
|
||||||
const secondaryIcon = props.data.active ?
|
const secondaryIcon = props.data.active ?
|
||||||
@@ -167,9 +175,9 @@ const CloudSyncTab = (props) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
margin: 4,
|
margin: 4,
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
minHeight: expanded ? 250 : "inherit",
|
minHeight: expanded ? 250 : "inherit",
|
||||||
maxHeight: expanded ? 300 : "inherit",
|
maxHeight: expanded ? 300 : "inherit",
|
||||||
boxShadow: "none",
|
boxShadow: "none",
|
||||||
@@ -188,13 +196,13 @@ const CloudSyncTab = (props) => {
|
|||||||
<Avatar>{primaryIcon}</Avatar>
|
<Avatar>{primaryIcon}</Avatar>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
style={{ textTransform: "capitalize", color: "#F1F1F1", fontSize: 14, fontWeight: 400, }}
|
style={{ textTransform: "capitalize", color: theme.palette.text.primary, fontSize: 14, fontWeight: 400, }}
|
||||||
primary={primary}
|
primary={shownName}
|
||||||
/>
|
/>
|
||||||
{isCloud && userdata.support === true ?
|
{isCloud && userdata.support === true ?
|
||||||
<Tooltip title="Edit features (support users only)">
|
<Tooltip title="Edit features (support users only)">
|
||||||
<EditIcon
|
<EditIcon
|
||||||
color="secondary"
|
color="textPrimary"
|
||||||
style={{ marginRight: 10, cursor: "pointer", }}
|
style={{ marginRight: 10, cursor: "pointer", }}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -475,7 +483,7 @@ const CloudSyncTab = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
toast("Cloud Syncronization successfully set up!");
|
toast("Cloud Syncronization successfully set up!");
|
||||||
setOrgSyncResponse(
|
setOrgSyncResponse(
|
||||||
"Successfully started syncronization. Cloud features you now have access to can be seen below."
|
"Successfully started syncronization. Cloud/Hybrid features are available below."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,20 +535,20 @@ const CloudSyncTab = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div style={{padding: "27px 10px 19px 27px",}}>
|
<div style={{padding: "27px 10px 19px 27px",}}>
|
||||||
<div style={{ marginBottom: 20 }}>
|
<div style={{ marginBottom: 20 }}>
|
||||||
<h2
|
<Typography variant="h5"
|
||||||
style={{ marginBottom: 8, marginTop: 0, color: "#ffffff" }}
|
style={{ marginBottom: 8, marginTop: 0, fontWeight: 500}}
|
||||||
>
|
>
|
||||||
Cloud syncronization
|
Cloud syncronization
|
||||||
</h2>
|
</Typography>
|
||||||
<span style={{ color: "#C8C8C8", fontSize: 16, fontWeight: 400, }}>
|
<Typography variant="body2" style={{ color: theme.palette.text.secondary, fontSize: 16, fontWeight: 400, }}>
|
||||||
What does <a href="/docs/organizations#cloud_sync" target="_blank" rel="noopener noreferrer" style={{ color: "rgba(255, 132, 68, 1)", fontSize: 16, textDecoration: 'none', }}>cloud sync</a> do? Cloud synchronization is a way of getting more out of Shuffle. Shuffle will ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach.
|
What does <a href="/docs/organizations#cloud_sync" target="_blank" rel="noopener noreferrer" style={{ color: theme.palette.linkColor, fontSize: 16, textDecoration: 'none', }}>cloud sync</a> do? Cloud synchronization is a way of getting more out of Shuffle. Shuffle will ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach. This will by default back up apps and workflows.
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isCloud ? (
|
{isCloud ? (
|
||||||
<div style={{ marginTop: 15, display: "flex" }}>
|
<div style={{ marginTop: 15, display: "flex" }}>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Typography style={{fontWeight: 400, fontSize: 16, color: "#F1F1F1"}}>
|
<Typography style={{fontWeight: 400, fontSize: 16, color: theme.palette.text.secondary}}>
|
||||||
Currently syncronizing:{" "}
|
Currently syncronizing:{" "}
|
||||||
{selectedOrganization.cloud_sync_active === true
|
{selectedOrganization.cloud_sync_active === true
|
||||||
? <span style={{ color: "#4CFD72", fontSize: 16, marginLeft: 16}}>True</span>
|
? <span style={{ color: "#4CFD72", fontSize: 16, marginLeft: 16}}>True</span>
|
||||||
@@ -561,28 +569,31 @@ const CloudSyncTab = (props) => {
|
|||||||
marginRight: 10,
|
marginRight: 10,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
fontFamily: theme.typography.fontFamily,
|
fontFamily: theme.typography.fontFamily,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Your Api key
|
Your Api key
|
||||||
</Typography>
|
</Typography>
|
||||||
{userSettings?.apikey === undefined || userSettings?.apikey === null || userSettings?.apikey?.length <=0 ? (
|
{userSettings?.apikey === undefined || userSettings?.apikey === null || userSettings?.apikey?.length <=0 ? (
|
||||||
<Skeleton variant="rectangular" animation="wave" sx={{backgroundColor: '#212121', border: '1px solid #646464', width: 500, height: 50, marginTop: 2 }}/>
|
<Skeleton variant="rectangular" animation="wave" sx={{backgroundColor: theme.palette.loaderColor, border: '1px solid #646464', width: 500, height: 50, marginTop: 2 }}/>
|
||||||
):
|
):
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<TextField
|
<TextField
|
||||||
color="primary"
|
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
borderRadius: theme.palette.textFieldStyle.borderRadius,
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
maxWidth: 500,
|
maxWidth: 500,
|
||||||
height: 35
|
height: 35
|
||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
sx: {
|
sx: {
|
||||||
height: "35px",
|
height: "35px",
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
backgroundColor: '#212121',
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
borderRadius: theme.palette.textFieldStyle.borderRadius,
|
||||||
},
|
},
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
@@ -639,14 +650,15 @@ const CloudSyncTab = (props) => {
|
|||||||
<TextField
|
<TextField
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
marginRight: 10,
|
marginRight: 10,
|
||||||
height: 35,
|
height: 35,
|
||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: "35px",
|
height: "35px",
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -701,17 +713,19 @@ const CloudSyncTab = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<h2 style={{ marginLeft: 5, marginTop: 40, marginBottom: 5 }}>
|
<Typography variant="h5" style={{ marginLeft: 5, marginTop: 40, marginBottom: 5 }}>
|
||||||
Features
|
{isCloud ? "Cloud" : "Hybrid"} Features
|
||||||
</h2>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 24, fontSize: 16, fontWeight: 400, marginLeft: 5, color: "#C8C8C8" }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 24, fontSize: 16, fontWeight: 400, marginLeft: 5, color: theme.palette.text.secondary }}>
|
||||||
Features and Limitations that are currently available to you in your Cloud or Hybrid Organization. App Executions (App Runs) reset monthly. If the organization is a customer or in a trial, these features limitations are not always enforced. </Typography>
|
Features and Limitations that are currently available to you in your Cloud or Hybrid Organization. App Executions (App Runs) reset monthly. If the organization is a customer or in a trial, these features limitations are not always enforced. </Typography>
|
||||||
<Grid container style={{ width: "100%", marginBottom: 15, }}>
|
<Grid container style={{ width: "100%", marginBottom: 15, }}>
|
||||||
|
|
||||||
{selectedOrganization.sync_features === undefined ||
|
{selectedOrganization.sync_features === undefined ||
|
||||||
selectedOrganization.sync_features === null
|
selectedOrganization.sync_features === null
|
||||||
? <Grid container spacing={2} justifyContent="center">
|
? <Grid container spacing={2} justifyContent="center">
|
||||||
|
|
||||||
{[...Array(18)].map((_, i) => (
|
{[...Array(18)].map((_, i) => (
|
||||||
|
|
||||||
<Grid item xs={12} sm={6} md={4} key={i}>
|
<Grid item xs={12} sm={6} md={4} key={i}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -728,7 +742,7 @@ const CloudSyncTab = (props) => {
|
|||||||
variant="rectangular"
|
variant="rectangular"
|
||||||
height={50}
|
height={50}
|
||||||
width={343}
|
width={343}
|
||||||
sx={{ backgroundColor: '#1a1a1a', display: 'flex', borderRadius: 1 }}
|
sx={{ backgroundColor: theme.palette.loaderColor, display: 'flex', borderRadius: 1 }}
|
||||||
animation="wave"
|
animation="wave"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -750,6 +764,13 @@ const CloudSyncTab = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newkey = key.replaceAll("_", " ");
|
const newkey = key.replaceAll("_", " ");
|
||||||
|
|
||||||
|
// Rewrites to frontend names
|
||||||
|
var newname = newkey
|
||||||
|
if (newkey === "app executions") {
|
||||||
|
newname = "app runs"
|
||||||
|
}
|
||||||
|
|
||||||
const griditem = {
|
const griditem = {
|
||||||
primary: newkey,
|
primary: newkey,
|
||||||
secondary:
|
secondary:
|
||||||
@@ -764,6 +785,8 @@ const CloudSyncTab = (props) => {
|
|||||||
data_collection: "None",
|
data_collection: "None",
|
||||||
active: item.active,
|
active: item.active,
|
||||||
icon: <PolylineIcon style={{ color: "#1a1a1a" }} />,
|
icon: <PolylineIcon style={{ color: "#1a1a1a" }} />,
|
||||||
|
|
||||||
|
newname: newname,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -0,0 +1,205 @@
|
|||||||
|
import React, { useState, useEffect, useContext, memo } from "react";
|
||||||
|
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
import { getTheme } from "../theme.jsx";
|
||||||
|
import { GetIconInfo } from "../views/Workflows2.jsx";
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
Typography,
|
||||||
|
Paper,
|
||||||
|
LinearProgress,
|
||||||
|
Grid,
|
||||||
|
Button,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Rocket as RocketIcon,
|
||||||
|
FilterAlt as FilterAltIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
|
const CollectIngestModal = (props) => {
|
||||||
|
const { globalUrl, open, setOpen } = props;
|
||||||
|
|
||||||
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
|
if (open === undefined || open === null) {
|
||||||
|
console.error("CollectIngestModal: 'open' prop is required.");
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setOpen === undefined || setOpen === null) {
|
||||||
|
console.error("CollectIngestModal: 'setOpen' prop is required.");
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const startIngestion = (appname, index) => {
|
||||||
|
console.log("APPNAME:", appname, "INDEX:", index)
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
"app_name": appname,
|
||||||
|
"label": appname,
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${globalUrl}/api/v2/workflows/generate`
|
||||||
|
fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
console.log("Ingestion started successfully:", data);
|
||||||
|
toast.success(`Ingestion for ${appname} started successfully!`);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Error starting ingestion:", error);
|
||||||
|
toast.error(`Failed to start ingestion for ${appname}. Please try again.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const IngestItem = (props) => {
|
||||||
|
const { type, index } = props
|
||||||
|
|
||||||
|
const [hovering, setHovering] = useState(false);
|
||||||
|
const [isFinished, setIsFinished] = useState(false);
|
||||||
|
|
||||||
|
const appname = type
|
||||||
|
const ingestedAmount = 20
|
||||||
|
|
||||||
|
const iconDetails = GetIconInfo({
|
||||||
|
"app_name": appname,
|
||||||
|
"name": appname,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
//<Grid item xs={hovering ? 12 : 5.9}
|
||||||
|
<Grid item xs={12}
|
||||||
|
style={{
|
||||||
|
minHeight: hovering ? 225 : 145,
|
||||||
|
maxHeight: hovering ? 225 : 145,
|
||||||
|
cursor: "pointer",
|
||||||
|
position: "relative",
|
||||||
|
transition: "all 0.3s ease-in-out",
|
||||||
|
|
||||||
|
borderRadius: theme.palette.borderRadius,
|
||||||
|
border: hovering ? `2px solid ${theme.palette.primary.main}` : isFinished ? `2px solid ${theme.palette.success.main}` : `2px solid ${theme.palette.secondary.main}`,
|
||||||
|
textAlign: "center",
|
||||||
|
marginBottom: 5,
|
||||||
|
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
onMouseEnter={() => setHovering(true)}
|
||||||
|
onMouseLeave={() => setHovering(false)}
|
||||||
|
>
|
||||||
|
<div style={{marginTop: 35, marginBottom: 35, }}>
|
||||||
|
{iconDetails?.originalIcon && (
|
||||||
|
iconDetails?.originalIcon
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Typography variant="h4" style={{marginTop: 10, }}>
|
||||||
|
|
||||||
|
{appname}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button variant="contained" onClick={() => {
|
||||||
|
toast.info("Starting ingest for relevant apps")
|
||||||
|
startIngestion(appname, index)
|
||||||
|
}}>
|
||||||
|
Start Ingestion
|
||||||
|
</Button>
|
||||||
|
{hovering ?
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{isFinished ?
|
||||||
|
<div>
|
||||||
|
<Typography variant="body1" style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 10,
|
||||||
|
left: 10,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
}}>
|
||||||
|
{ingestedAmount} / X
|
||||||
|
</Typography>
|
||||||
|
<LinearProgress
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
variant="determinate"
|
||||||
|
fullWidth value={{ingestedAmount}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
PaperProps={{
|
||||||
|
sx: {
|
||||||
|
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
|
||||||
|
border: theme?.palette?.DialogStyle?.border,
|
||||||
|
minWidth: 500,
|
||||||
|
minHeight: 700,
|
||||||
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
zIndex: 1000,
|
||||||
|
'& .MuiDialogContent-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
'& .MuiDialogTitle-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
'& .MuiDialogActions-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
open={open}
|
||||||
|
onClose={() => {
|
||||||
|
setOpen(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent style={{ paddingLeft: "30px", paddingRight: '30px', backgroundColor: theme.palette.DialogStyle.backgroundColor, }}>
|
||||||
|
|
||||||
|
<Typography variant="h6" style={{ color: theme.palette.text.primary, marginBottom: 20 }}>
|
||||||
|
<FilterAltIcon style={{ verticalAlign: "middle", marginRight: 10 }} />
|
||||||
|
Collection and Ingestion
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container>
|
||||||
|
<IngestItem type="Ingest Tickets" index={1} />
|
||||||
|
<IngestItem type="Enable Threat feeds" index={2} />
|
||||||
|
<IngestItem type="Track Assets" index={2} />
|
||||||
|
<IngestItem type="Enable Search" index={2} />
|
||||||
|
<IngestItem type="Enable Mitre Att&ck techniques" index={2} />
|
||||||
|
<IngestItem type="Enable Detection Rules" index={2} />
|
||||||
|
<IngestItem type="Ingest Logs" index={2} />
|
||||||
|
</Grid>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CollectIngestModal
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
import { useInterval } from "react-powerhooks";
|
import { useInterval } from "react-powerhooks";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import WorkflowValidationTimeline from "../components/WorkflowValidationTimeline.jsx"
|
import WorkflowValidationTimeline from "../components/WorkflowValidationTimeline.jsx"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
Collapse,
|
Collapse,
|
||||||
IconButton,
|
IconButton,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import {
|
import {
|
||||||
FavoriteBorder as FavoriteBorderIcon,
|
FavoriteBorder as FavoriteBorderIcon,
|
||||||
Error as ErrorIcon,
|
Error as ErrorIcon,
|
||||||
@@ -76,6 +76,8 @@ const ConfigureWorkflow = (props) => {
|
|||||||
const [showFinalizeAnimation, setShowFinalizeAnimation] = React.useState(false);
|
const [showFinalizeAnimation, setShowFinalizeAnimation] = React.useState(false);
|
||||||
const [loopRunning, setLoopRunning] = useState(false)
|
const [loopRunning, setLoopRunning] = useState(false)
|
||||||
const [checkStarted, setCheckStarted] = React.useState(false);
|
const [checkStarted, setCheckStarted] = React.useState(false);
|
||||||
|
const { themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (requiredActions.length === 0) {
|
if (requiredActions.length === 0) {
|
||||||
@@ -631,7 +633,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
if (aa !== undefined) {
|
if (aa !== undefined) {
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
})
|
})
|
||||||
|
|
||||||
const timestamp = new Date().getTime()
|
const timestamp = new Date().getTime()
|
||||||
@@ -799,7 +801,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
border: filled ? `1px solid ${theme.palette.green}` : "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, width: "100%", padding: 12, cursor: filled ? "default" : "pointer",
|
border: filled ? `1px solid ${theme.palette.green}` : theme.palette.textFieldStyle.border, borderRadius: theme.palette?.borderRadius, width: "100%", padding: 12, cursor: filled ? "default" : "pointer",
|
||||||
}}
|
}}
|
||||||
id="app-config"
|
id="app-config"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ const countries = [
|
|||||||
suggested: true,
|
suggested: true,
|
||||||
},
|
},
|
||||||
{ code: 'GA', label: 'Gabon', phone: '241' },
|
{ code: 'GA', label: 'Gabon', phone: '241' },
|
||||||
{ code: 'GB', label: 'United Kingdom', phone: '44' },
|
|
||||||
{ code: 'GD', label: 'Grenada', phone: '1-473' },
|
{ code: 'GD', label: 'Grenada', phone: '1-473' },
|
||||||
{ code: 'GE', label: 'Georgia', phone: '995' },
|
{ code: 'GE', label: 'Georgia', phone: '995' },
|
||||||
{ code: 'GF', label: 'French Guiana', phone: '594' },
|
{ code: 'GF', label: 'French Guiana', phone: '594' },
|
||||||
@@ -178,7 +177,6 @@ const countries = [
|
|||||||
{ code: 'IE', label: 'Ireland', phone: '353' },
|
{ code: 'IE', label: 'Ireland', phone: '353' },
|
||||||
{ code: 'IL', label: 'Israel', phone: '972' },
|
{ code: 'IL', label: 'Israel', phone: '972' },
|
||||||
{ code: 'IM', label: 'Isle of Man', phone: '44' },
|
{ code: 'IM', label: 'Isle of Man', phone: '44' },
|
||||||
{ code: 'IN', label: 'India', phone: '91' },
|
|
||||||
{
|
{
|
||||||
code: 'IO',
|
code: 'IO',
|
||||||
label: 'British Indian Ocean Territory',
|
label: 'British Indian Ocean Territory',
|
||||||
@@ -390,12 +388,6 @@ const countries = [
|
|||||||
},
|
},
|
||||||
{ code: 'UA', label: 'Ukraine', phone: '380' },
|
{ code: 'UA', label: 'Ukraine', phone: '380' },
|
||||||
{ code: 'UG', label: 'Uganda', phone: '256' },
|
{ code: 'UG', label: 'Uganda', phone: '256' },
|
||||||
{
|
|
||||||
code: 'US',
|
|
||||||
label: 'United States',
|
|
||||||
phone: '1',
|
|
||||||
suggested: true,
|
|
||||||
},
|
|
||||||
{ code: 'UY', label: 'Uruguay', phone: '598' },
|
{ code: 'UY', label: 'Uruguay', phone: '598' },
|
||||||
{ code: 'UZ', label: 'Uzbekistan', phone: '998' },
|
{ code: 'UZ', label: 'Uzbekistan', phone: '998' },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import {
|
|||||||
AvatarGroup,
|
AvatarGroup,
|
||||||
} from "@mui/material"
|
} from "@mui/material"
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const CreatorGrid = props => {
|
const CreatorGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, isHeader } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, isHeader } = props
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
|
|||||||
@@ -65,80 +65,83 @@ export const LoadStats = (globalUrl, cachekey) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DashboardBarchart = (props) => {
|
const DashboardBarchart = (props) => {
|
||||||
const { timelineData, title, height, } = props;
|
// this is clearly unfinished and not worth my time.
|
||||||
var inputHeight = 15
|
// refer to health page to see how i made it work there w/o using chartjs
|
||||||
if (height !== undefined && height !== null) {
|
|
||||||
inputHeight = height
|
|
||||||
}
|
|
||||||
|
|
||||||
const barOptions = {
|
// const { timelineData, title, height, } = props;
|
||||||
plugins: {
|
// var inputHeight = 15
|
||||||
tooltip: {
|
// if (height !== undefined && height !== null) {
|
||||||
enabled: true, // Ensure tooltips are enabled
|
// inputHeight = height
|
||||||
},
|
// }
|
||||||
},
|
|
||||||
tooltips: {
|
|
||||||
mode: 'index',
|
|
||||||
intersect: false,
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
padding: {
|
|
||||||
top: 0, // Adjust the top padding as needed
|
|
||||||
bottom: -10, // Adjust the bottom padding as needed
|
|
||||||
left: 0, // Adjust the left padding as needed
|
|
||||||
right: 0, // Adjust the right padding as needed
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: false,
|
|
||||||
},
|
|
||||||
yAxes: [{
|
|
||||||
ticks: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
beginAtZero: false,
|
|
||||||
}],
|
|
||||||
xAxes: [{
|
|
||||||
ticks: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
beginAtZero: false,
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
tooltips: {
|
|
||||||
callbacks: {
|
|
||||||
label: function (tooltipItem, data) {
|
|
||||||
const label = data.labels[tooltipItem.index]
|
|
||||||
return label.split('\n')[0]
|
|
||||||
},
|
|
||||||
afterLabel: function (tooltipItem, data) {
|
|
||||||
const amount = tooltipItem.value === undefined || tooltipItem.value === null ? 0 : tooltipItem.value
|
|
||||||
return `Amount: ${amount}`
|
|
||||||
},
|
|
||||||
title: function () {
|
|
||||||
return title === undefined ? '' : title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
// const barOptions = {
|
||||||
<Bar
|
// plugins: {
|
||||||
data={timelineData}
|
// tooltip: {
|
||||||
options={barOptions}
|
// enabled: true, // Ensure tooltips are enabled
|
||||||
height={inputHeight}
|
// },
|
||||||
getElementAtEvent={(elements) => {
|
// },
|
||||||
if (elements && elements.length > 0) {
|
// tooltips: {
|
||||||
//toast("Click event")
|
// mode: 'index',
|
||||||
console.log("Clicked: ", elements)
|
// intersect: false,
|
||||||
}
|
// },
|
||||||
}}
|
// legend: {
|
||||||
/>
|
// display: false
|
||||||
)
|
// },
|
||||||
|
// layout: {
|
||||||
|
// padding: {
|
||||||
|
// top: 0, // Adjust the top padding as needed
|
||||||
|
// bottom: -10, // Adjust the bottom padding as needed
|
||||||
|
// left: 0, // Adjust the left padding as needed
|
||||||
|
// right: 0, // Adjust the right padding as needed
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// scales: {
|
||||||
|
// y: {
|
||||||
|
// beginAtZero: false,
|
||||||
|
// },
|
||||||
|
// yAxes: [{
|
||||||
|
// ticks: {
|
||||||
|
// display: false
|
||||||
|
// },
|
||||||
|
// beginAtZero: false,
|
||||||
|
// }],
|
||||||
|
// xAxes: [{
|
||||||
|
// ticks: {
|
||||||
|
// display: false
|
||||||
|
// },
|
||||||
|
// beginAtZero: false,
|
||||||
|
// }]
|
||||||
|
// },
|
||||||
|
// tooltips: {
|
||||||
|
// callbacks: {
|
||||||
|
// label: function (tooltipItem, data) {
|
||||||
|
// const label = data.labels[tooltipItem.index]
|
||||||
|
// return label.split('\n')[0]
|
||||||
|
// },
|
||||||
|
// afterLabel: function (tooltipItem, data) {
|
||||||
|
// const amount = tooltipItem.value === undefined || tooltipItem.value === null ? 0 : tooltipItem.value
|
||||||
|
// return `Amount: ${amount}`
|
||||||
|
// },
|
||||||
|
// title: function () {
|
||||||
|
// return title === undefined ? '' : title
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <Bar
|
||||||
|
// data={timelineData}
|
||||||
|
// options={barOptions}
|
||||||
|
// height={inputHeight}
|
||||||
|
// getElementAtEvent={(elements) => {
|
||||||
|
// if (elements && elements.length > 0) {
|
||||||
|
// //toast("Click event")
|
||||||
|
// console.log("Clicked: ", elements)
|
||||||
|
// }
|
||||||
|
// }}
|
||||||
|
// />
|
||||||
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DashboardBarchart;
|
export default DashboardBarchart;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const DocsGrid = props => {
|
const DocsGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, } = props
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import OrgHeaderexpanded from "../components/OrgHeaderexpandedNew.jsx";
|
|||||||
import OrgHeader from '../components/OrgHeaderNew.jsx';
|
import OrgHeader from '../components/OrgHeaderNew.jsx';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import CloudSyncTab from '../components/CloudSyncTab.jsx';
|
import CloudSyncTab from '../components/CloudSyncTab.jsx';
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
import { getTheme } from '../theme.jsx';
|
||||||
import {
|
import {
|
||||||
FileCopy as FileCopyIcon,
|
FileCopy as FileCopyIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
@@ -10,6 +12,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
const EditOrgTab = (props) => {
|
const EditOrgTab = (props) => {
|
||||||
@@ -33,6 +36,9 @@ const EditOrgTab = (props) => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
const handleStatusChange = (event) => {
|
const handleStatusChange = (event) => {
|
||||||
const { value } = event.target;
|
const { value } = event.target;
|
||||||
setSelectedStatus(value);
|
setSelectedStatus(value);
|
||||||
@@ -283,23 +289,23 @@ If you're interested, please let me know a time that works for you, or set up a
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: "100%", boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: '#212121', borderRadius: '16px', }}>
|
<div style={{ width: "100%", boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor, borderRadius: '16px', }}>
|
||||||
<div style={{ height: "100%", width: "100%", overflowX: 'hidden', scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}} >
|
<div style={{ height: "100%", width: "100%", overflowX: 'hidden', scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}} >
|
||||||
<div style={{ marginBottom: 20 }}>
|
<div style={{ marginBottom: 20 }}>
|
||||||
<div style={{display:"flex"}}>
|
<div style={{display:"flex"}}>
|
||||||
<div style={{width:'70%'}}>
|
<div style={{width:'70%'}}>
|
||||||
<h2 style={{ marginBottom: 8, marginTop: 0, color: "#ffffff" }}>Organization overview</h2>
|
<Typography variant='h3' sx={{ marginBottom: "15px", marginTop: 0, }}>Organization overview</Typography>
|
||||||
<span style={{ color: "#9E9E9E" }}>
|
<Typography variant="body2" style={{ color: theme.palette.text.secondary, fontSize: 16 }}>
|
||||||
On this page organization admins can configure organisations, and sub-orgs (MSSP).{" "}
|
On this page organization admins can configure organisations, and sub-orgs (MSSP).{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/organizations#organization"
|
href="/docs/organizations#organization"
|
||||||
style={{ color: "#FF8444" }}
|
style={{ color: theme.palette.linkColor, }}
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div style={{display:"flex", alignItems:"center", marginLeft:50}}>
|
<div style={{display:"flex", alignItems:"center", marginLeft:50}}>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useContext } from "react";
|
import React, { useEffect, useContext } from "react";
|
||||||
import theme from '../theme.jsx';
|
import { getTheme } from '../theme.jsx';
|
||||||
import { isMobile } from "react-device-detect"
|
import { isMobile } from "react-device-detect"
|
||||||
import { MuiChipsInput } from "mui-chips-input";
|
import { MuiChipsInput } from "mui-chips-input";
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
@@ -46,7 +46,7 @@ import {
|
|||||||
Slider,
|
Slider,
|
||||||
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import {
|
import {
|
||||||
DatePicker,
|
DatePicker,
|
||||||
LocalizationProvider,
|
LocalizationProvider,
|
||||||
@@ -69,7 +69,8 @@ const EditWorkflow = (props) => {
|
|||||||
const { globalUrl, workflow, setWorkflow, modalOpen, setModalOpen, showUpload, usecases, setNewWorkflow, appFramework, isEditing, userdata, apps, saveWorkflow, expanded, scrollTo, setRealtimeMarkdown, boxWidth, setBoxWidth, } = props
|
const { globalUrl, workflow, setWorkflow, modalOpen, setModalOpen, showUpload, usecases, setNewWorkflow, appFramework, isEditing, userdata, apps, saveWorkflow, expanded, scrollTo, setRealtimeMarkdown, boxWidth, setBoxWidth, } = props
|
||||||
|
|
||||||
const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove
|
const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove
|
||||||
|
const {themeMode, brandColor} = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode, brandColor)
|
||||||
const [submitLoading, setSubmitLoading] = React.useState(false);
|
const [submitLoading, setSubmitLoading] = React.useState(false);
|
||||||
const [showMoreClicked, setShowMoreClicked] = React.useState(isEditing !== false ? true : false);
|
const [showMoreClicked, setShowMoreClicked] = React.useState(isEditing !== false ? true : false);
|
||||||
|
|
||||||
@@ -187,7 +188,7 @@ const EditWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newWorkflow = isEditing === true ? false : true
|
const newWorkflow = isEditing === true ? false : true
|
||||||
const priority = userdata === undefined || userdata === null ? null : userdata.priorities.find(prio => prio.type === "usecase" && prio.active === true)
|
const priority = userdata === undefined || userdata === null || userdata.priorities === null || userdata.priorities === undefined ? null : userdata?.priorities?.find(prio => prio.type === "usecase" && prio.active === true)
|
||||||
var upload = "";
|
var upload = "";
|
||||||
var total_count = 0
|
var total_count = 0
|
||||||
|
|
||||||
@@ -203,26 +204,24 @@ const EditWorkflow = (props) => {
|
|||||||
setModalOpen(false);
|
setModalOpen(false);
|
||||||
}}
|
}}
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
style: {
|
sx: {
|
||||||
color: "white",
|
color: theme.palette.DialogStyle.color,
|
||||||
minWidth: isMobile ? "90%" : 650,
|
minWidth: isMobile ? "90%" : "650px",
|
||||||
maxWidth: isMobile ? "90%" : 650,
|
maxWidth: isMobile ? "90%" : "650px",
|
||||||
minHeight: 400,
|
minHeight: "400px",
|
||||||
paddingTop: 25,
|
|
||||||
paddingLeft: 50,
|
|
||||||
//minWidth: isMobile ? "90%" : newWorkflow === true ? 1000 : 550,
|
//minWidth: isMobile ? "90%" : newWorkflow === true ? 1000 : 550,
|
||||||
//maxWidth: isMobile ? "90%" : newWorkflow === true ? 1000 : 550,
|
//maxWidth: isMobile ? "90%" : newWorkflow === true ? 1000 : 550,
|
||||||
borderRadius: theme.palette.borderRadius,
|
borderRadius: theme.palette.DialogStyle.borderRadius,
|
||||||
backgroundColor: "black",
|
backgroundColor: themeMode === "dark" ? "black" : theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle style={{ padding: 30, paddingBottom: 0, zIndex: 1000, }}>
|
<DialogTitle style={{ padding: 30, paddingBottom: 0, zIndex: 1000, paddingTop: "25px", paddingLeft: "50px"}}>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<div style={{ flex: 1, color: "rgba(255,255,255,0.9)" }}>
|
<div style={{ flex: 1, color: theme.palette.textColor }}>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<Typography variant="h4" style={{ flex: 9, }}>
|
<Typography variant="h4" style={{ flex: 9, marginTop: 25, }}>
|
||||||
{newWorkflow ? "New" : "Editing"} workflow
|
{newWorkflow ? "New" : "Editing"} Workflow
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{newWorkflow === true ? null :
|
{newWorkflow === true ? null :
|
||||||
@@ -248,7 +247,7 @@ const EditWorkflow = (props) => {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 20, maxWidth: 440, }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginTop: 20, maxWidth: 440, }}>
|
||||||
Workflows can be built from scratch, or from templates. <a href="/usecases2" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Usecases</a> can help you discover next steps, and you can <a href="/search?tab=workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>search</a> for them directly. <a href="/docs/workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Learn more</a>
|
Workflows can be built from scratch, or from templates. <a href="/usecases2" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: theme.palette.linkColor }}>Usecases</a> can help you discover next steps, and you can <a href="/search?tab=workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: theme.palette.linkColor }}>search</a> for them directly. <a href="/docs/workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color:theme.palette.linkColor }}>Learn more</a>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<div style={{marginTop: 10, marginBottom: 10, marginRight: 50, }}>
|
<div style={{marginTop: 10, marginBottom: 10, marginRight: 50, }}>
|
||||||
@@ -288,20 +287,21 @@ const EditWorkflow = (props) => {
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div style={{
|
<div style={{
|
||||||
borderTop: "1px solid rgba(255,255,255,0.5)",
|
borderTop: theme.palette.defaultBorder,
|
||||||
width: 600,
|
width: 600,
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
right: 20,
|
right: 20,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
zIndex: 1002,
|
zIndex: 1002,
|
||||||
backgroundColor: theme.palette.backgroundColor,
|
|
||||||
height: 75,
|
height: 75,
|
||||||
paddingTop: 20,
|
paddingTop: 20,
|
||||||
paddingLeft: 75,
|
paddingLeft: 30,
|
||||||
|
backgroundColor: themeMode === "dark" ? "#262626" : theme.palette.DialogStyle.backgroundColor,
|
||||||
}}>
|
}}>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{}}
|
style={{}}
|
||||||
|
id="save_workflow_button"
|
||||||
disabled={name.length === 0 || submitLoading === true}
|
disabled={name.length === 0 || submitLoading === true}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSubmitLoading(true)
|
setSubmitLoading(true)
|
||||||
@@ -387,7 +387,7 @@ const EditWorkflow = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogContent style={{ paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 200, }}>
|
<DialogContent style={{ paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 400, paddingLeft: 50, }}>
|
||||||
<div style={{ minWidth: newWorkflow ? 500 : 550, maxWidth: newWorkflow ? 450 : 500, }}>
|
<div style={{ minWidth: newWorkflow ? 500 : 550, maxWidth: newWorkflow ? 450 : 500, }}>
|
||||||
<TextField
|
<TextField
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
@@ -395,7 +395,7 @@ const EditWorkflow = (props) => {
|
|||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -406,6 +406,7 @@ const EditWorkflow = (props) => {
|
|||||||
label="Name"
|
label="Name"
|
||||||
autoFocus
|
autoFocus
|
||||||
fullWidth
|
fullWidth
|
||||||
|
id="Enter-Workflow-Name"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div style={{ display: "flex", marginTop: 10, }}>
|
<div style={{ display: "flex", marginTop: 10, }}>
|
||||||
@@ -467,7 +468,7 @@ const EditWorkflow = (props) => {
|
|||||||
style={{ flex: 1, maxHeight: 120, overflow: "auto", }}
|
style={{ flex: 1, maxHeight: 120, overflow: "auto", }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
placeholder="Tags"
|
placeholder="Tags"
|
||||||
@@ -543,6 +544,8 @@ const EditWorkflow = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormControlLabel value="test" control={<Radio />} label="Test" />
|
<FormControlLabel value="test" control={<Radio />} label="Test" />
|
||||||
|
<FormControlLabel value="staging" control={<Radio />} label="Staging" />
|
||||||
|
<FormControlLabel value="preprod" control={<Radio />} label="Pre-production" />
|
||||||
<FormControlLabel value="production" control={<Radio />} label="Production" />
|
<FormControlLabel value="production" control={<Radio />} label="Production" />
|
||||||
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
@@ -577,12 +580,20 @@ const EditWorkflow = (props) => {
|
|||||||
<Typography variant="h4" style={{ marginTop: 50, }}>
|
<Typography variant="h4" style={{ marginTop: 50, }}>
|
||||||
Multi-Tenancy, Backups & Security
|
Multi-Tenancy, Backups & Security
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 30, marginBottom: 10, }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginTop: 30, marginBottom: 10, }}>
|
||||||
Multi-Tenant Workflows. Make one workflow, and keep a separate, synced copy in all your tenants. Control distributed auth, runtime locations, files, datastore keys etc. (contact support@shuffler.io if you want a demo. Please try it!)
|
Control mechanisms for multi-tenancy, backups, and security.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ?
|
<Typography variant="h6" style={{ marginTop: 50, }}>
|
||||||
|
Multi-Tenant Workflows
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, marginBottom: 10, }}>
|
||||||
|
Make one workflow, and keep a separate, synced copy in your other tenants. Control distributed auth, runtime locations, files, datastore keys etc. Can only distribute from parent org to child org. Need help trying it? <a href="https://shuffler.io/contact" target="_blank" style={{color: "#f85a3e", textDecoration: "none",}}>Contact us for a demo</a>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ?
|
||||||
|
|
||||||
userdata.orgs.filter(org => org.creator_org === userdata.active_org.id).length === 0 ?
|
userdata.orgs.filter(org => org.creator_org === userdata.active_org.id).length === 0 ?
|
||||||
userdata.active_org.creator_org === undefined || userdata.active_org.creator_org === null || userdata.active_org.creator_org === "" ?
|
userdata.active_org.creator_org === undefined || userdata.active_org.creator_org === null || userdata.active_org.creator_org === "" ?
|
||||||
<Typography variant="body2" style={{ marginTop: 10, color: "rgba(255,255,255,0.7)" }}>
|
<Typography variant="body2" style={{ marginTop: 10, color: "rgba(255,255,255,0.7)" }}>
|
||||||
@@ -600,6 +611,7 @@ const EditWorkflow = (props) => {
|
|||||||
multiple
|
multiple
|
||||||
style={{ marginTop: 10, }}
|
style={{ marginTop: 10, }}
|
||||||
value={innerWorkflow.suborg_distribution === undefined || innerWorkflow.suborg_distribution === null ? ["none"] : innerWorkflow.suborg_distribution}
|
value={innerWorkflow.suborg_distribution === undefined || innerWorkflow.suborg_distribution === null ? ["none"] : innerWorkflow.suborg_distribution}
|
||||||
|
disabled={workflow?.parentorg_workflow !== undefined && workflow?.parentorg_workflow !== null && workflow?.parentorg_workflow.length > 0}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
var newvalue = e.target.value
|
var newvalue = e.target.value
|
||||||
if (newvalue.length > 1 && newvalue[0] === "none") {
|
if (newvalue.length > 1 && newvalue[0] === "none") {
|
||||||
@@ -1274,7 +1286,7 @@ const EditWorkflow = (props) => {
|
|||||||
|
|
||||||
|
|
||||||
{newWorkflow === true ?
|
{newWorkflow === true ?
|
||||||
<span style={{ marginTop: 30, }}>
|
<span style={{ paddingTop: 30 }}>
|
||||||
<Typography variant="h6" style={{ marginLeft: 30, paddingBottom: 0, }}>
|
<Typography variant="h6" style={{ marginLeft: 30, paddingBottom: 0, }}>
|
||||||
Relevant Workflows
|
Relevant Workflows
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { memo, useContext, useEffect, useState } from 'react';
|
import React, { memo, useContext, useEffect, useState } from 'react';
|
||||||
import theme from "../theme.jsx";
|
import { getTheme } from "../theme.jsx";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -62,6 +62,9 @@ const EnvironmentTab = memo((props) => {
|
|||||||
const [selectedSubOrg, setSelectedSubOrg] = React.useState([]);
|
const [selectedSubOrg, setSelectedSubOrg] = React.useState([]);
|
||||||
const [showLocationActionModal, setShowLocationActionModal] = React.useState(undefined)
|
const [showLocationActionModal, setShowLocationActionModal] = React.useState(undefined)
|
||||||
|
|
||||||
|
const { themeMode, supportEmail, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getEnvironments();
|
getEnvironments();
|
||||||
@@ -370,7 +373,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast(
|
toast(
|
||||||
"Failed dismissing alert. Please contact support@shuffler.io if this persists.",
|
`Failed dismissing alert. Please contact ${supportEmail} if this persists.`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -512,11 +515,11 @@ const EnvironmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<span style={{ color: "white" }}>Add Location</span>
|
<Typography variant='h5' color="textPrimary" >Add Location</Typography>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div>
|
<div>
|
||||||
Location Name
|
<Typography variant='body2' color="textPrimary">Location Name</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor,}}
|
style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor,}}
|
||||||
@@ -524,7 +527,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: "50px",
|
height: "50px",
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -539,19 +542,18 @@ const EnvironmentTab = memo((props) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{loginInfo} {/* Assuming loginInfo is part of the relevant content */}
|
{loginInfo}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", color: "#ff8544" }}
|
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", color: theme.palette.primary.main, }}
|
||||||
onClick={() => setModalOpen(false)}
|
onClick={() => setModalOpen(false)}
|
||||||
color="primary"
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", backgroundColor: "#ff8544", color: "#1a1a1a" }}
|
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
submitEnvironment(modalUser); // Assuming modalUser is available
|
submitEnvironment(modalUser); // Assuming modalUser is available
|
||||||
}}
|
}}
|
||||||
@@ -733,9 +735,9 @@ const EnvironmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<div style={{ color: "rgba(255,255,255,0.9)" }}>
|
<Typography variant='h5' color="textPrimary" >
|
||||||
Select sub-org to distribute Environments
|
Select sub-org to distribute Environments
|
||||||
</div>
|
</Typography>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
|
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
|
||||||
<MenuItem value="none" onClick={()=> {handleSelectSubOrg(null, "none")}}>None</MenuItem>
|
<MenuItem value="none" onClick={()=> {handleSelectSubOrg(null, "none")}}>None</MenuItem>
|
||||||
@@ -778,7 +780,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
|
|
||||||
<div style={{ display: "flex", marginTop: 20 }}>
|
<div style={{ display: "flex", marginTop: 20 }}>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#ff8544" }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: theme.palette.primary.main }}
|
||||||
onClick={() => setShowDistributionPopup(false)}
|
onClick={() => setShowDistributionPopup(false)}
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
@@ -786,7 +788,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#1a1a1a", backgroundColor: "#ff8544", marginLeft: 10 }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, marginLeft: 10 }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
changeDistribution(selectedEnvironment, selectedSubOrg);
|
changeDistribution(selectedEnvironment, selectedSubOrg);
|
||||||
}}
|
}}
|
||||||
@@ -800,27 +802,27 @@ const EnvironmentTab = memo((props) => {
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: '#212121',borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", }}>
|
<div style={{ width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor,borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: theme.palette.defaultBorder, }}>
|
||||||
{modalView}
|
{modalView}
|
||||||
{EnvironmentDistributionModal}
|
{EnvironmentDistributionModal}
|
||||||
<div style={{ height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin' }}>
|
<div style={{ height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin' }}>
|
||||||
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
|
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
|
||||||
<div style={{ marginBottom: 20 }}>
|
<div style={{ marginBottom: 20 }}>
|
||||||
<h2 style={{ marginBottom: 8, marginTop: 0, color: "#ffffff" }}>Runtime Locations</h2>
|
<Typography variant='h5' color="textPrimary" style={{ marginBottom: 8, marginTop: 0,}}>Runtime Locations</Typography>
|
||||||
<span style={{ color: textColor }}>
|
<Typography variant='body2' color="textSecondary">
|
||||||
Decides which Orborus <b>runtime location</b> to run your workflows in. Previously called Environments. <br /> If you have scale problems, <a href="https://shuffler.io/docs/configuration#high-availability" target="_blank" rel="noopener noreferrer" style={{ color: "#FF8444" }}>check the docs</a> or talk to our team: support@shuffler.io.
|
Decides which Orborus <b>runtime location</b> to run your workflows in. Previously called Environments. <br /> If you have scale problems, <a href="https://shuffler.io/docs/configuration#high-availability" target="_blank" rel="noopener noreferrer" style={{ color: theme.palette.linkColor }}>check the docs</a> or talk to our team: {supportEmail}.
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/organizations#locations"
|
href="/docs/organizations#locations"
|
||||||
style={{ color: "#FF8444" }}
|
style={{ color: theme.palette.linkColor, }}
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
style={{ backgroundColor: '#ff8544', color: "#1a1a1a", borderRadius: 4, textTransform: "capitalize", fontSize: 16, }}
|
style={{ borderRadius: 4, textTransform: "capitalize", fontSize: 16, }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => setModalOpen(true)}
|
onClick={() => setModalOpen(true)}
|
||||||
@@ -828,9 +830,9 @@ const EnvironmentTab = memo((props) => {
|
|||||||
Add Location
|
Add Location
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
style={{ backgroundColor: "#2F2F2F", borderRadius: 4, width: 81, height: 40, marginLeft: 16, marginRight: 15 }}
|
style={{ borderRadius: 4, width: 81, height: 40, marginLeft: 16, marginRight: 15 }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="secondary"
|
||||||
onClick={getEnvironments}
|
onClick={getEnvironments}
|
||||||
>
|
>
|
||||||
<CachedIcon />
|
<CachedIcon />
|
||||||
@@ -851,7 +853,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -873,7 +875,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
minWidth: 800,
|
minWidth: 800,
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{["Type", "Status", "Scale", "Pipeline", "Name", "Type", "Queue", "Actions", "Distribution"].map((header, index) => {
|
{["Type", "Status", "Scale", "Pipeline", "Name", "Type", "Queue", "Actions", "Distribution"].map((header, index) => {
|
||||||
@@ -901,7 +903,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "80px 80px 80px 120px 120px 120px 120px 350px 150px",
|
gridTemplateColumns: "80px 80px 80px 120px 120px 120px 120px 350px 150px",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
height: 40,
|
height: 40,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
@@ -919,7 +921,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -941,9 +943,9 @@ const EnvironmentTab = memo((props) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bgColor = "#212121";
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = "#1A1A1A";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there's a notification for it in userdata.priorities
|
// Check if there's a notification for it in userdata.priorities
|
||||||
@@ -1013,7 +1015,9 @@ const EnvironmentTab = memo((props) => {
|
|||||||
environment.name === "Cloud" ? (
|
environment.name === "Cloud" ? (
|
||||||
<Tooltip title="Cloud" placement="top">
|
<Tooltip title="Cloud" placement="top">
|
||||||
<CloudIcon
|
<CloudIcon
|
||||||
style={{ color: "rgba(255,255,255,0.8)" }}
|
style={{
|
||||||
|
color: themeMode === "dark" ? "#CCCCCC" : "#333333",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : environment.run_type === "docker" ? (
|
) : environment.run_type === "docker" ? (
|
||||||
@@ -1075,7 +1079,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
:
|
:
|
||||||
<span>IP / label: {environment?.running_ip?.split(":")[0]}. May stay running up to a minute after stopping Orborus.</span>
|
<span>IP / label: {environment?.running_ip?.split(":")[0]}. May stay running up to a minute after stopping Orborus.</span>
|
||||||
:
|
:
|
||||||
"Cloud is automatically configured. Reachout to support@shuffler.io if you have any questions."
|
`Cloud is automatically configured. Reachout to ${supportEmail} if you have any questions.`
|
||||||
}
|
}
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
@@ -1169,7 +1173,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
environment.Type === "cloud" ?
|
environment.Type === "cloud" ?
|
||||||
<Tooltip title={"Make a new environment to set up a Datalake node. Please contact support@shuffler.io if this is something you want to see on Cloud directly."} placement="top">
|
<Tooltip title={`Make a new environment to set up a Datalake node. Please contact ${supportEmail} if this is something you want to see on Cloud directly.`} placement="top">
|
||||||
<CancelIcon style={{ color: "rgba(255,255,255,0.3)" }} />
|
<CancelIcon style={{ color: "rgba(255,255,255,0.3)" }} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
:
|
:
|
||||||
@@ -1267,13 +1271,12 @@ const EnvironmentTab = memo((props) => {
|
|||||||
/>
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
style={{
|
style={{
|
||||||
minWidth: 300,
|
minWidth: 350,
|
||||||
overflow: "hidden",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex", flexWrap: "nowrap" }}>
|
<div style={{ display: "flex", flexWrap: "nowrap" }}>
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
style={{ borderRadius: "5px 5px 5px 5px", flexWrap: "nowrap" }}
|
style={{ borderRadius: "5px 5px 5px 5px", flexWrap: "nowrap", width: "100%" }}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -1369,7 +1372,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<IconButton disabled={environment.Type === "cloud"} onClick={()=> {setIsExpanded(prev => !prev)}}>
|
<IconButton disabled={environment.Type === "cloud"} onClick={()=> {setIsExpanded(prev => !prev)}}>
|
||||||
{listItemExpanded === index ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
{listItemExpanded === index ? <ExpandLessIcon sx={{color: theme.palette.text.primary}} /> : <ExpandMoreIcon sx={{color: theme.palette.text.primary}}/>}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
@@ -1420,7 +1423,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
<Collapse in={listItemExpanded === index} timeout="auto" unmountOnExit>
|
<Collapse in={listItemExpanded === index} timeout="auto" unmountOnExit>
|
||||||
<Grid container justifyContent="center" style={{minWidth: 850, maxWidth: 850, }}>
|
<Grid container justifyContent="center" style={{minWidth: 850, maxWidth: 850, }}>
|
||||||
<Grid item xs={12} sm={8} md={6}>
|
<Grid item xs={12} sm={8} md={6}>
|
||||||
<div style={{minWidth: 700, maxWidth: 700, minHeight: 350, display: 'flex', justifyContent: "center", backgroundColor: "transparent", }}>
|
<div style={{minWidth: 750, maxWidth: 750, minHeight: 350, display: 'flex', justifyContent: "center", backgroundColor: "transparent", }}>
|
||||||
<div style={{ paddingTop: 50, paddingBottom: 100, }}>
|
<div style={{ paddingTop: 50, paddingBottom: 100, }}>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
Self-Hosted Orborus instance
|
Self-Hosted Orborus instance
|
||||||
@@ -1443,7 +1446,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
value={0}
|
value={0}
|
||||||
label=<span>
|
label=<span style={{color: theme.palette.text.secondary, }}>
|
||||||
<img
|
<img
|
||||||
src="/icons/docker.svg"
|
src="/icons/docker.svg"
|
||||||
style={{ width: 20, height: 20, marginRight: 10, }}
|
style={{ width: 20, height: 20, marginRight: 10, }}
|
||||||
@@ -1452,32 +1455,32 @@ const EnvironmentTab = memo((props) => {
|
|||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
value={1}
|
value={1}
|
||||||
label=<span>
|
label=<span style={{color: theme.palette.text.secondary, }}>
|
||||||
<img
|
<img
|
||||||
src="/icons/docker.svg"
|
src="/icons/docker.svg"
|
||||||
style={{ width: 20, height: 20, marginRight: 10, }}
|
style={{ width: 20, height: 20, marginRight: 10,}}
|
||||||
/> Scale
|
/> Scale
|
||||||
</span>
|
</span>
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
value={2}
|
value={2}
|
||||||
label=<span>
|
label=<span style={{color: theme.palette.text.secondary, }}>
|
||||||
<img
|
<img
|
||||||
src="/icons/k8s.svg"
|
src="/icons/k8s.svg"
|
||||||
style={{ width: 20, height: 20, marginRight: 10, }}
|
style={{ width: 20, height: 20, marginRight: 10 }}
|
||||||
/> k8s
|
/> k8s
|
||||||
</span>
|
</span>
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
||||||
{installationTab === 2 ?
|
{installationTab === 2 ?
|
||||||
<span>
|
<Typography variant='body2' color="textSecondary">
|
||||||
Check our <a href="https://docs.docker.com/get-started/get-docker/" target="_blank" rel="noopener noreferrer" style={{textDecoration: "none", color: "#f85a3e",}}>Kubernetes documentation</a> for more information on how to run Shuffle on Kubernetes. The status of the node will change when connected.
|
Check our <a href="https://docs.docker.com/get-started/get-docker/" target="_blank" rel="noopener noreferrer" style={{textDecoration: "none", color: "#f85a3e",}}>Kubernetes documentation</a> for more information on how to run Shuffle on Kubernetes. The status of the node will change when connected.
|
||||||
</span>
|
</Typography>
|
||||||
:
|
:
|
||||||
<span>
|
<Typography variant='body2' color="textSecondary">
|
||||||
1. <a href="https://docs.docker.com/get-started/get-docker/" target="_blank" rel="noopener noreferrer" style={{textDecoration: "none", color: "#f85a3e",}}>Ensure Docker is installed</a> and the target server can reach '{globalUrl}'
|
1. <a href="https://docs.docker.com/get-started/get-docker/" target="_blank" rel="noopener noreferrer" style={{textDecoration: "none", color: "#f85a3e",}}>Ensure Docker is installed</a> and the target server can reach '{globalUrl}'
|
||||||
</span>
|
</Typography>
|
||||||
}
|
}
|
||||||
|
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -1501,13 +1504,19 @@ const EnvironmentTab = memo((props) => {
|
|||||||
>
|
>
|
||||||
<div style={{ display: "flex", position: "relative", }}>
|
<div style={{ display: "flex", position: "relative", }}>
|
||||||
<code
|
<code
|
||||||
contenteditable="true"
|
contentEditable="true"
|
||||||
id="orborus_command"
|
id="orborus_command"
|
||||||
style={{
|
style={{
|
||||||
// Wrap if larger than X
|
|
||||||
whiteSpace: "pre-wrap",
|
whiteSpace: "pre-wrap",
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
marginRight: 30,
|
marginRight: 30,
|
||||||
|
backgroundColor: themeMode === "dark" ? "#1e1e1e" : "#f5f5f5",
|
||||||
|
color: themeMode === "dark" ? "#f8f8f2" : "#333",
|
||||||
|
padding: "8px",
|
||||||
|
borderRadius: "4px",
|
||||||
|
fontFamily: "monospace",
|
||||||
|
fontSize: 18,
|
||||||
|
border: themeMode === "dark" ? "1px solid #555" : "1px solid #ddd",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{getOrborusCommand(environment)}
|
{getOrborusCommand(environment)}
|
||||||
@@ -1532,7 +1541,8 @@ const EnvironmentTab = memo((props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider style={{marginTop: 25, marginBottom: 10, }}/>
|
<Divider style={{marginTop: 25, marginBottom: 10, }}/>
|
||||||
Configure HTTP Proxies: <Checkbox
|
<div style={{display: 'flex', alignItems: 'center', }}>
|
||||||
|
<Typography variant='body2' color="textSecondary">Configure HTTP Proxies:</Typography> <Checkbox
|
||||||
id="shuffle_skip_proxies"
|
id="shuffle_skip_proxies"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (commandController.proxies === undefined) {
|
if (commandController.proxies === undefined) {
|
||||||
@@ -1545,8 +1555,10 @@ const EnvironmentTab = memo((props) => {
|
|||||||
setUpdate(Math.random())
|
setUpdate(Math.random())
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<div />
|
<div />
|
||||||
Disable Pipelines & Data Lake: <Checkbox
|
<div style={{display: 'flex', alignItems: 'center', }}>
|
||||||
|
<Typography variant='body2' color="textSecondary">Disable Pipelines & Data Lake:</Typography> <Checkbox
|
||||||
id="shuffle_skip_pipelines"
|
id="shuffle_skip_pipelines"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (commandController.pipelines === undefined) {
|
if (commandController.pipelines === undefined) {
|
||||||
@@ -1559,6 +1571,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import {
|
|||||||
|
|
||||||
import Dropzone from "../components/Dropzone.jsx";
|
import Dropzone from "../components/Dropzone.jsx";
|
||||||
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import { Context } from "../context/ContextApi.jsx";
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
|
||||||
const Files = memo((props) => {
|
const Files = memo((props) => {
|
||||||
@@ -58,6 +58,8 @@ const Files = memo((props) => {
|
|||||||
const [openEditor, setOpenEditor] = React.useState(false);
|
const [openEditor, setOpenEditor] = React.useState(false);
|
||||||
const [renderTextBox, setRenderTextBox] = React.useState(false);
|
const [renderTextBox, setRenderTextBox] = React.useState(false);
|
||||||
const [loadFileModalOpen, setLoadFileModalOpen] = React.useState(false);
|
const [loadFileModalOpen, setLoadFileModalOpen] = React.useState(false);
|
||||||
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
const [field1, setField1] = React.useState("");
|
const [field1, setField1] = React.useState("");
|
||||||
const [field2, setField2] = React.useState("");
|
const [field2, setField2] = React.useState("");
|
||||||
@@ -442,7 +444,7 @@ const Files = memo((props) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#ff8544" }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: theme.palette.primary.main }}
|
||||||
onClick={() => setLoadFileModalOpen(false)}
|
onClick={() => setLoadFileModalOpen(false)}
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
@@ -450,7 +452,7 @@ const Files = memo((props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#1a1a1a", backgroundColor: "#ff8544" }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, }}
|
||||||
disabled={downloadUrl.length === 0 || !downloadUrl.includes("http")}
|
disabled={downloadUrl.length === 0 || !downloadUrl.includes("http")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleGithubValidation();
|
handleGithubValidation();
|
||||||
@@ -517,9 +519,9 @@ const Files = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<div style={{ color: "rgba(255,255,255,0.9)" }}>
|
<Typography variant="h5" color="textPrimary" >
|
||||||
Select sub-org to distribute files
|
Select sub-org to distribute files
|
||||||
</div>
|
</Typography>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
|
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
|
||||||
<MenuItem value="none" onClick={()=> {handleSelectSubOrg(null, "none")}}>None</MenuItem>
|
<MenuItem value="none" onClick={()=> {handleSelectSubOrg(null, "none")}}>None</MenuItem>
|
||||||
@@ -562,15 +564,14 @@ const Files = memo((props) => {
|
|||||||
|
|
||||||
<div style={{ display: "flex", marginTop: 20 }}>
|
<div style={{ display: "flex", marginTop: 20 }}>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#ff8544" }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: theme.palette.primary.main }}
|
||||||
onClick={() => setShowDistributionPopup(false)}
|
onClick={() => setShowDistributionPopup(false)}
|
||||||
color="primary"
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#1a1a1a", backgroundColor: "#ff8544", marginLeft: 10 }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, marginLeft: 10 }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
changeDistribution(fileIdSelectedForDistribution, selectedSubOrg);
|
changeDistribution(fileIdSelectedForDistribution, selectedSubOrg);
|
||||||
}}
|
}}
|
||||||
@@ -906,27 +907,27 @@ const Files = memo((props) => {
|
|||||||
onDrop={uploadFile}
|
onDrop={uploadFile}
|
||||||
>
|
>
|
||||||
{fileDistributionModal}
|
{fileDistributionModal}
|
||||||
<div style={{width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: '#212121',borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", }}>
|
<div style={{width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor,borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: theme.palette.defaultBorder, }}>
|
||||||
|
|
||||||
<div style={{height: "100%", maxHeight: 1700,overflowY: 'auto', scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
|
<div style={{height: "100%", maxHeight: 1700,overflowY: 'auto', scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
|
||||||
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin' }}>
|
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin' }}>
|
||||||
<DownloadFileIcon setLoadFileModalOpen={setLoadFileModalOpen} isSelectedFiles={isSelectedFiles} />
|
<DownloadFileIcon setLoadFileModalOpen={setLoadFileModalOpen} isSelectedFiles={isSelectedFiles} />
|
||||||
|
|
||||||
{fileDownloadModal}
|
{fileDownloadModal}
|
||||||
|
|
||||||
<div style={{ marginTop: isSelectedFiles ? 2: 20, marginBottom:20 }}>
|
<div style={{ marginTop: isSelectedFiles ? 2: 20, marginBottom:20 }}>
|
||||||
<h2 style={{ display: isSelectedFiles ? null : "inline", marginTop: isSelectedFiles?0:null, marginBottom: isSelectedFiles?8:null, color: "#FFFFFF"}}>Files</h2>
|
<Typography variant="h5" color="textPrimary" style={{ display: isSelectedFiles ? null : "inline", marginTop: isSelectedFiles?0:null, marginBottom: isSelectedFiles?8:null, fontWeight: 500}}>Files</Typography>
|
||||||
<span style={{ marginLeft: isSelectedFiles ? null : 25, color:isSelectedFiles?"#9E9E9E":null}}>
|
<Typography variant="body2" color="textSecondary" style={{ marginLeft: isSelectedFiles ? null : 25,}}>
|
||||||
Files from Workflows are a way to store as well as edit files.{" "}
|
Files from Workflows are a way to store as well as edit files.{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="https://shuffler.io/docs/organizations#files"
|
href="https://shuffler.io/docs/organizations#files"
|
||||||
style={{ textDecoration: isSelectedFiles ? null:"none", color: isSelectedFiles? "#FF8444": "#f85a3e" }}
|
style={{ textDecoration: isSelectedFiles ? null:"none", color: theme.palette.linkColor }}
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -937,7 +938,7 @@ const Files = memo((props) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
upload.click();
|
upload.click();
|
||||||
}}
|
}}
|
||||||
style={{backgroundColor: isSelectedFiles?'#ff8544':null, color:isSelectedFiles?"#212121":null, textTransform: 'none',fontSize: 16, borderRadius:isSelectedFiles?4:null, width:isSelectedFiles?143:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null,}}
|
style={{ textTransform: 'none',fontSize: 16, borderRadius:isSelectedFiles?4:null, width:isSelectedFiles?143:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null,}}
|
||||||
>
|
>
|
||||||
Upload files
|
Upload files
|
||||||
</Button>
|
</Button>
|
||||||
@@ -958,9 +959,9 @@ const Files = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: 16, marginRight: 15, backgroundColor:isSelectedFiles?"#2F2F2F":null,borderRadius:isSelectedFiles?4:null, width:isSelectedFiles?81:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null, }}
|
style={{ marginLeft: 16, marginRight: 15, borderRadius:isSelectedFiles?4:null, width:isSelectedFiles?81:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null, }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="secondary"
|
||||||
onClick={() => getFiles(selectedCategory)}
|
onClick={() => getFiles(selectedCategory)}
|
||||||
>
|
>
|
||||||
<CachedIcon />
|
<CachedIcon />
|
||||||
@@ -976,7 +977,6 @@ const Files = memo((props) => {
|
|||||||
labelId="input-namespace-select-label"
|
labelId="input-namespace-select-label"
|
||||||
id="input-namespace-select-id"
|
id="input-namespace-select-id"
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
|
||||||
minWidth: 122,
|
minWidth: 122,
|
||||||
maxWidth: 122,
|
maxWidth: 122,
|
||||||
height: 35,
|
height: 35,
|
||||||
@@ -1013,7 +1013,6 @@ const Files = memo((props) => {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
key={index}
|
key={index}
|
||||||
value={data}
|
value={data}
|
||||||
style={{ color: "white" }}
|
|
||||||
>
|
>
|
||||||
{data.replaceAll("_", " ")}
|
{data.replaceAll("_", " ")}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@@ -1044,8 +1043,8 @@ const Files = memo((props) => {
|
|||||||
Please note that your selected files ({selectedFileId?.length}) will be moved to the <kbd>{updateToThisCategory}</kbd> category.
|
Please note that your selected files ({selectedFileId?.length}) will be moved to the <kbd>{updateToThisCategory}</kbd> category.
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => setShowFileCategoryPopup(false)} style={{fontSize: 16, textTransform: 'none'}}>Close</Button>
|
<Button onClick={() => setShowFileCategoryPopup(false)} style={{fontSize: 16, textTransform: 'none', color: theme.palette.primary.main }}>Close</Button>
|
||||||
<Button onClick={() => handleUpdateFileCategory(updateToThisCategory)} style={{fontSize: 16, textTransform: 'none', color: "#1a1a1a", backgroundColor: "#ff8544"}}>Update</Button>
|
<Button variant="contained" color="primary" onClick={() => handleUpdateFileCategory(updateToThisCategory)} style={{fontSize: 16, textTransform: 'none', }}>Update</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -1055,8 +1054,9 @@ const Files = memo((props) => {
|
|||||||
{renderTextBox ?
|
{renderTextBox ?
|
||||||
<Tooltip title={"Close"} style={{}} aria-label={""}>
|
<Tooltip title={"Close"} style={{}} aria-label={""}>
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: 5, marginRight: 15, height: 35, borderRadius: 4, backgroundColor: "#494949", textTransform: 'none', fontSize: 16, color: "#f1f1f1" }}
|
style={{ marginLeft: 5, marginRight: 15, height: 35, borderRadius: 4, textTransform: 'none', fontSize: 16, }}
|
||||||
color="primary"
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setRenderTextBox(false);
|
setRenderTextBox(false);
|
||||||
console.log(" close clicked")
|
console.log(" close clicked")
|
||||||
@@ -1068,8 +1068,9 @@ const Files = memo((props) => {
|
|||||||
:
|
:
|
||||||
<Tooltip title={"Add new file category"} style={{}} aria-label={""}>
|
<Tooltip title={"Add new file category"} style={{}} aria-label={""}>
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: 5, marginRight: 15, width: 169, height: 35, borderRadius: 4, backgroundColor: "#494949", textTransform: 'none', fontSize: 16, color: "#f1f1f1" }}
|
style={{whiteSpace: 'nowrap', textWrap: 'nowrap', marginLeft: 5, marginRight: 15, width: 169, height: 35, borderRadius: 4, textTransform: 'none', fontSize: 16, }}
|
||||||
color="primary"
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setRenderTextBox(true);
|
setRenderTextBox(true);
|
||||||
}}
|
}}
|
||||||
@@ -1096,7 +1097,8 @@ const Files = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
height: 35,
|
height: 35,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
@@ -1133,7 +1135,7 @@ const Files = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -1151,7 +1153,7 @@ const Files = memo((props) => {
|
|||||||
>
|
>
|
||||||
<ListItem
|
<ListItem
|
||||||
style={{
|
style={{
|
||||||
borderBottom: "1px solid #494949" ,
|
borderBottom: theme.palette.defaultBorder ,
|
||||||
display: "table-row"
|
display: "table-row"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -1198,7 +1200,7 @@ const Files = memo((props) => {
|
|||||||
padding: index === 0 ? "0px 8px 8px 15px" : "0px 8px 8px 8px",
|
padding: index === 0 ? "0px 8px 8px 15px" : "0px 8px 8px 8px",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
verticalAlign: "middle"
|
verticalAlign: "middle"
|
||||||
}}
|
}}
|
||||||
primaryTypographyProps={{
|
primaryTypographyProps={{
|
||||||
@@ -1215,7 +1217,7 @@ const Files = memo((props) => {
|
|||||||
key={rowIndex}
|
key={rowIndex}
|
||||||
style={{
|
style={{
|
||||||
display: "table-row",
|
display: "table-row",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(8)
|
{Array(8)
|
||||||
@@ -1232,7 +1234,7 @@ const Files = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
height: "20px",
|
height: "20px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
@@ -1257,9 +1259,9 @@ const Files = memo((props) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bgColor = isSelectedFiles ? "#212121":"#27292d";
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = isSelectedFiles ? "#1A1A1A":"#1f2023";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
const isDistributed = file?.suborg_distribution?.length > 0 ? true : false;
|
const isDistributed = file?.suborg_distribution?.length > 0 ? true : false;
|
||||||
const filenamesplit = file.filename.split(".")
|
const filenamesplit = file.filename.split(".")
|
||||||
@@ -1425,9 +1427,20 @@ const Files = memo((props) => {
|
|||||||
readFileData(file)
|
readFileData(file)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img src="/icons/editIcon.svg" alt="edit icon"
|
<svg
|
||||||
style={{color: iseditable ? "white" : "grey", width: 24, height: 24}}
|
width="24"
|
||||||
/>
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.1038 4.66848C16.3158 4.45654 16.5674 4.28843 16.8443 4.17373C17.1212 4.05903 17.418 4 17.7177 4C18.0174 4 18.3142 4.05903 18.5911 4.17373C18.868 4.28843 19.1196 4.45654 19.3315 4.66848C19.5435 4.88041 19.7116 5.13201 19.8263 5.40891C19.941 5.68582 20 5.9826 20 6.28232C20 6.58204 19.941 6.87882 19.8263 7.15573C19.7116 7.43263 19.5435 7.68423 19.3315 7.89617L8.43807 18.7896L4 20L5.21038 15.5619L16.1038 4.66848Z"
|
||||||
|
stroke={themeMode=== "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1470,15 +1483,39 @@ const Files = memo((props) => {
|
|||||||
downloadFile(file);
|
downloadFile(file);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img src="/icons/downloadIcon.svg" alt="download icon"
|
<svg
|
||||||
style={{
|
width="24"
|
||||||
width: 24, height: 24,
|
height="24"
|
||||||
color:
|
viewBox="0 0 24 24"
|
||||||
file.status === "active"
|
fill="none"
|
||||||
? "white"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
: "grey",
|
>
|
||||||
}}
|
<rect
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fill={themeMode === "dark" ? "#212121" : "#EDEDED"}
|
||||||
|
fillOpacity="0.02"
|
||||||
/>
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.22595 16.4463L11.7792 19.9995L15.3324 16.4463"
|
||||||
|
stroke={file.status === "active" ? (themeMode === "dark" ? "#F1F1F1" : "black") : "grey"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M11.7792 12.0049V19.9997"
|
||||||
|
stroke={file.status === "active" ? (themeMode === "dark" ? "#F1F1F1" : "black") : "grey"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M19.6676 17.415C20.4399 16.8719 21.019 16.0968 21.321 15.2023C21.6229 14.3078 21.632 13.3403 21.3468 12.4403C21.0617 11.5402 20.4971 10.7545 19.7352 10.197C18.9732 9.6396 18.0534 9.33948 17.1092 9.34021H15.99C15.7228 8.299 15.2229 7.33196 14.5279 6.5119C13.8329 5.69184 12.961 5.04013 11.9777 4.60583C10.9944 4.17153 9.92534 3.96596 8.85109 4.00459C7.77684 4.04322 6.72535 4.32505 5.77578 4.82886C4.82621 5.33267 4.00331 6.04534 3.36902 6.9132C2.73474 7.78106 2.30559 8.78151 2.11391 9.83922C1.92222 10.8969 1.97297 11.9844 2.26236 13.0196C2.55174 14.0549 3.07221 15.011 3.78459 15.816"
|
||||||
|
stroke={file.status === "active" ? (themeMode === "dark" ? "#F1F1F1" : "black") : "grey"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1496,7 +1533,31 @@ const Files = memo((props) => {
|
|||||||
toast(file.id + " copied to clipboard");
|
toast(file.id + " copied to clipboard");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img src="/icons/copyIcon.svg" alt="copy icon" style={{ color: "white", width: 24, height: 24 }} />
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fillOpacity="1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 4H7.6C7.17565 4 6.76869 4.16857 6.46863 4.46863C6.16857 4.76869 6 5.17565 6 5.6V18.4C6 18.8243 6.16857 19.2313 6.46863 19.5314C6.76869 19.8314 7.17565 20 7.6 20H17.2C17.6243 20 18.0313 19.8314 18.3314 19.5314C18.6314 19.2313 18.8 18.8243 18.8 18.4V8.8L14 4Z"
|
||||||
|
stroke={themeMode === "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 4V8.8H18.8"
|
||||||
|
stroke={themeMode === "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@@ -1570,7 +1631,6 @@ const Files = memo((props) => {
|
|||||||
disabled={userdata?.active_org?.role !== "admin" || (selectedOrganization.creator_org !== undefined && selectedOrganization.creator_org !== null && selectedOrganization.creator_org !== "" ) ? true : false}
|
disabled={userdata?.active_org?.role !== "admin" || (selectedOrganization.creator_org !== undefined && selectedOrganization.creator_org !== null && selectedOrganization.creator_org !== "" ) ? true : false}
|
||||||
checked={isDistributed}
|
checked={isDistributed}
|
||||||
style={{ }}
|
style={{ }}
|
||||||
color="secondary"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowDistributionPopup(true)
|
setShowDistributionPopup(true)
|
||||||
if(file?.suborg_distribution?.length > 0){
|
if(file?.suborg_distribution?.length > 0){
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
|
import React, { useRef, useState, useEffect, useLayoutEffect, useContext } from "react";
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useParams, useNavigate, Link } from "react-router-dom";
|
import { useParams, useNavigate, Link } from "react-router-dom";
|
||||||
import theme from '../theme.jsx';
|
import { getTheme } from '../theme.jsx';
|
||||||
//import { useAlert
|
//import { useAlert
|
||||||
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
@@ -112,6 +113,8 @@ const AuthenticationOauth2 = (props) => {
|
|||||||
authenticationType.client_secret !== null &&
|
authenticationType.client_secret !== null &&
|
||||||
authenticationType.client_secret.length > 0
|
authenticationType.client_secret.length > 0
|
||||||
);
|
);
|
||||||
|
const {themeMode, brandColor} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
const [clientId, setClientId] = React.useState(defaultConfigSet ? authenticationType.client_id : "");
|
const [clientId, setClientId] = React.useState(defaultConfigSet ? authenticationType.client_id : "");
|
||||||
const [clientSecret, setClientSecret] = React.useState(defaultConfigSet ? authenticationType.client_secret : "");
|
const [clientSecret, setClientSecret] = React.useState(defaultConfigSet ? authenticationType.client_secret : "");
|
||||||
@@ -724,7 +727,7 @@ const AuthenticationOauth2 = (props) => {
|
|||||||
style={{ margin: 4, minHeight: 30, maxHeight: 30, borderRadius: theme.palette?.borderRadius, }}
|
style={{ margin: 4, minHeight: 30, maxHeight: 30, borderRadius: theme.palette?.borderRadius, }}
|
||||||
src={selectedAction.large_image}
|
src={selectedAction.large_image}
|
||||||
/>
|
/>
|
||||||
<Typography style={{ margin: 0, marginLeft: 10, marginTop: 5,}} variant="body1">
|
<Typography style={{ margin: 0, marginLeft: 10, marginTop: 5, color: "#2f2f2f",}} variant="body1">
|
||||||
One-click Login
|
One-click Login
|
||||||
</Typography>
|
</Typography>
|
||||||
</span>
|
</span>
|
||||||
@@ -738,7 +741,7 @@ const AuthenticationOauth2 = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<div style={{ color: "white" }}>
|
<div style={{ color: theme.palette.text.primary }}>
|
||||||
Authenticate {selectedApp.name.replaceAll("_", " ")}
|
Authenticate {selectedApp.name.replaceAll("_", " ")}
|
||||||
</div>
|
</div>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
@@ -749,7 +752,7 @@ const AuthenticationOauth2 = (props) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="norefferer"
|
rel="norefferer"
|
||||||
href="/docs/apps#authentication"
|
href="/docs/apps#authentication"
|
||||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
style={{ textDecoration: "none", color: theme.palette.linkColor}}
|
||||||
>
|
>
|
||||||
{" "}
|
{" "}
|
||||||
Learn more about Oauth2 with Shuffle
|
Learn more about Oauth2 with Shuffle
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState, useContext } from "react";
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -69,6 +69,8 @@ const OrgHeader = (props) => {
|
|||||||
selectedOrganization.description
|
selectedOrganization.description
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { themeMode } = useContext(Context)
|
||||||
|
const {theme} = getTheme(themeMode)
|
||||||
|
|
||||||
const [file, setFile] = React.useState("");
|
const [file, setFile] = React.useState("");
|
||||||
const [fileBase64, setFileBase64] = React.useState(
|
const [fileBase64, setFileBase64] = React.useState(
|
||||||
@@ -364,10 +366,10 @@ const OrgHeader = (props) => {
|
|||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<div style={{ color: "rgba(255, 255, 255, 0.9)" }}>Upload Organization Image</div>
|
<div style={{ color: theme?.palette?.textColor}}>Upload Organization Image</div>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
{errorText}
|
{errorText}
|
||||||
<DialogContent style={{ color: "rgba(255, 255, 255, 0.65)" }}>
|
<DialogContent style={{ color: theme?.palette?.textColor }}>
|
||||||
<AvatarEditor
|
<AvatarEditor
|
||||||
ref={setEditorRef}
|
ref={setEditorRef}
|
||||||
image={croppedData}
|
image={croppedData}
|
||||||
@@ -389,7 +391,7 @@ const OrgHeader = (props) => {
|
|||||||
style={appIconStyle}
|
style={appIconStyle}
|
||||||
onClick={() => { upload.click(); }}
|
onClick={() => { upload.click(); }}
|
||||||
>
|
>
|
||||||
<AddAPhotoOutlinedIcon style={{ color: "rgba(255, 255, 255, 0.9)" }} />
|
<AddAPhotoOutlinedIcon style={{ color: theme?.palette?.textColor }} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Zoom In">
|
<Tooltip title="Zoom In">
|
||||||
@@ -399,7 +401,7 @@ const OrgHeader = (props) => {
|
|||||||
style={appIconStyle}
|
style={appIconStyle}
|
||||||
onClick={zoomIn}
|
onClick={zoomIn}
|
||||||
>
|
>
|
||||||
<ZoomInOutlinedIcon style={{ color: "rgba(255, 255, 255, 0.9)" }} />
|
<ZoomInOutlinedIcon style={{ color: theme?.palette?.textColor }} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Zoom Out">
|
<Tooltip title="Zoom Out">
|
||||||
@@ -409,7 +411,7 @@ const OrgHeader = (props) => {
|
|||||||
style={appIconStyle}
|
style={appIconStyle}
|
||||||
onClick={zoomOut}
|
onClick={zoomOut}
|
||||||
>
|
>
|
||||||
<ZoomOutOutlinedIcon style={{ color: "rgba(255, 255, 255, 0.9)" }} />
|
<ZoomOutOutlinedIcon style={{ color: theme?.palette?.textColor }} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Rotate">
|
<Tooltip title="Rotate">
|
||||||
@@ -419,7 +421,7 @@ const OrgHeader = (props) => {
|
|||||||
style={appIconStyle}
|
style={appIconStyle}
|
||||||
onClick={rotation}
|
onClick={rotation}
|
||||||
>
|
>
|
||||||
<LoopIcon style={{ color: "rgba(255, 255, 255, 0.9)" }} />
|
<LoopIcon style={{ color: theme?.palette?.textColor }} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
@@ -427,7 +429,7 @@ const OrgHeader = (props) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", color: "rgba(255, 255, 255, 0.9)" }}
|
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", color: theme?.palette?.textColor }}
|
||||||
onClick={onCancelSaveAppIcon}
|
onClick={onCancelSaveAppIcon}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -491,7 +493,7 @@ const OrgHeader = (props) => {
|
|||||||
<div style={{ marginLeft: 16, alignContent: "center" }}>
|
<div style={{ marginLeft: 16, alignContent: "center" }}>
|
||||||
<div >
|
<div >
|
||||||
<Button
|
<Button
|
||||||
style={{ backgroundColor: '#ff8544', fontSize: 16, textTransform: 'capitalize', color: "#212121", boxShadow: "none", borderRadius: 4, width: 128, height: 40 }}
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 128, height: 40 }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -503,9 +505,9 @@ const OrgHeader = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
style={{ backgroundColor: '#494949', fontSize: 16, textTransform: 'capitalize', color: "#ffffff", boxShadow: "none", marginTop: 20, borderRadius: 4, width: 128, height: 40 }}
|
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="secondary"
|
||||||
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", marginTop: 20, borderRadius: 4, width: 128, height: 40 }}
|
||||||
onClick={() => removeImage()}
|
onClick={() => removeImage()}
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { memo, useEffect, useState } from "react";
|
import React, { memo, useEffect, useState, useContext } from "react";
|
||||||
|
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
import theme from '../theme.jsx';
|
import { getTheme } from '../theme.jsx';
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
//import { useAlert
|
//import { useAlert
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -89,6 +90,8 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [openNotification, setOpenNotification] = React.useState(false);
|
const [openNotification, setOpenNotification] = React.useState(false);
|
||||||
|
const { themeMode, supportEmail, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
const handleStatusChange = (event) => {
|
const handleStatusChange = (event) => {
|
||||||
const { value } = event.target;
|
const { value } = event.target;
|
||||||
@@ -178,7 +181,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
const [uploadRepo, setUploadRepo] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_repo === undefined || selectedOrganization.defaults.workflow_upload_repo.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_repo)
|
const [uploadRepo, setUploadRepo] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_repo === undefined || selectedOrganization.defaults.workflow_upload_repo.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_repo)
|
||||||
const [uploadBranch, setUploadBranch] = React.useState(selectedOrganization.defaults === undefined ? defaultBranch : selectedOrganization.defaults.workflow_upload_branch === undefined || selectedOrganization.defaults.workflow_upload_branch.length === 0 ? defaultBranch : selectedOrganization.defaults.workflow_upload_branch)
|
const [uploadBranch, setUploadBranch] = React.useState(selectedOrganization.defaults === undefined ? defaultBranch : selectedOrganization.defaults.workflow_upload_branch === undefined || selectedOrganization.defaults.workflow_upload_branch.length === 0 ? defaultBranch : selectedOrganization.defaults.workflow_upload_branch)
|
||||||
const [uploadUsername, setUploadUsername] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_username === undefined || selectedOrganization.defaults.workflow_upload_username.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_username)
|
const [uploadUsername, setUploadUsername] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_username === undefined || selectedOrganization.defaults.workflow_upload_username.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_username)
|
||||||
const [uploadToken, setUploadToken] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_token === undefined || selectedOrganization.defaults.workflow_upload_token.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_token)
|
const [uploadToken, setUploadToken] = React.useState("")
|
||||||
const [regionStatus, setRegionStatus] = useState();
|
const [regionStatus, setRegionStatus] = useState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -199,9 +202,10 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
setUploadUsername(selectedOrganization?.defaults?.workflow_upload_username)
|
setUploadUsername(selectedOrganization?.defaults?.workflow_upload_username)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uploadToken !== selectedOrganization?.defaults?.workflow_upload_token) {
|
// Not showing the token in the UI (cause it's in plain text)
|
||||||
setUploadToken(selectedOrganization?.defaults?.workflow_upload_token)
|
// if (uploadToken !== selectedOrganization?.defaults?.workflow_upload_token) {
|
||||||
}
|
// setUploadToken(selectedOrganization?.defaults?.workflow_upload_token)
|
||||||
|
// }
|
||||||
}, [selectedOrganization])
|
}, [selectedOrganization])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -264,7 +268,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
|
|
||||||
const handleSendChangeRegionMail = (region) => {
|
const handleSendChangeRegionMail = (region) => {
|
||||||
if (selectedOrganization === undefined || selectedOrganization === null) {
|
if (selectedOrganization === undefined || selectedOrganization === null) {
|
||||||
toast.error("Failed to send request for changing region. Please contact support@shuffler.io.")
|
toast.error(`Failed to send request for changing region. Please contact ${supportEmail}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,30 +298,29 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
toast.error("Failed to send request for changing region. Please contact support@shuffler.io.")
|
toast.error(`Failed to send request for changing region. Please contact ${supportEmail}`)
|
||||||
} else {
|
} else {
|
||||||
toast.success("Successfully sent request for region change. We will process the move and contact you shortly.")
|
toast.success("Successfully sent request for region change. We will process the move and contact you shortly.")
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
toast.error("Failed to send request for changing region. Please contact support@shuffler.io.")
|
toast.error(`Failed to send request for changing region. Please contact ${supportEmail}`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSelectedRegion = (region) => {
|
const setSelectedRegion = (region) => {
|
||||||
|
|
||||||
// send a POST request to /api/v1/orgs/{org_id}/region with the region as the body
|
// send a POST request to /api/v1/orgs/{org_id}/region with the region as the body
|
||||||
if (region === "US") {
|
const regionMap = {
|
||||||
region = "us-west2"
|
"US": "us-west2",
|
||||||
} else if (region === "EU") {
|
"EU": "europe-west2",
|
||||||
region = "europe-west2"
|
"CA": "northamerica-northeast1",
|
||||||
} else if (region === "CA") {
|
"UK": "europe-west2",
|
||||||
region = "northamerica-northeast1"
|
"EU-2": "europe-west3",
|
||||||
} else if (region === "UK") {
|
"AUS": "australia-southeast1"
|
||||||
region = "europe-west2"
|
};
|
||||||
} else if (region === "EU-2") {
|
|
||||||
region = "europe-west3"
|
region = regionMap[region] || region;
|
||||||
}
|
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
dst_region: region
|
dst_region: region
|
||||||
@@ -336,7 +339,11 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
timeOut: 1000
|
timeOut: 1000
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
toast("Failed to change region!")
|
response.json().then((reason) => {
|
||||||
|
toast.error("Failed to change region: " + reason.reason)
|
||||||
|
}).catch((err) => {
|
||||||
|
toast.error("Failed to change region")
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
toast("Region changed successfully! Reloading in 5 seconds..")
|
toast("Region changed successfully! Reloading in 5 seconds..")
|
||||||
@@ -347,7 +354,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json();
|
// return responseJson
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +362,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
const orgSaveButton = (
|
const orgSaveButton = (
|
||||||
<Tooltip title="Save any unsaved data" placement="bottom">
|
<Tooltip title="Save any unsaved data" placement="bottom">
|
||||||
<Button
|
<Button
|
||||||
style={{ width: 244, height: 51, display: 'flex', justifyContent: 'center', textTransform: 'capitalize', padding: "16px, 24px, 16px, 24px", borderRadius: 4, backgroundColor: "#ff8544", color: "#1a1a1a", fontSize: 16, }}
|
style={{ width: 244, height: 51, display: 'flex', justifyContent: 'center', textTransform: 'capitalize', padding: "16px, 24px, 16px, 24px", borderRadius: 4, fontSize: 16, }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={
|
disabled={
|
||||||
@@ -441,11 +448,11 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
<Grid item xs={12} style={{}}>
|
<Grid item xs={12} style={{}}>
|
||||||
<span>
|
<span>
|
||||||
<div style={{}}>
|
<div style={{}}>
|
||||||
<div style={{ flex: "3", color: "white" }}>
|
<div style={{ flex: "3", color: theme.palette.text.primary }}>
|
||||||
<div style={{ marginTop: 8, display: "flex" }} />
|
<div style={{ marginTop: 8, display: "flex" }} />
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<div style={{ width: "100%", maxWidth: 434, marginRight: 10 }}>
|
<div style={{ width: "100%", maxWidth: 434, marginRight: 10 }}>
|
||||||
Name
|
<Typography variant="text" style={{color: theme.palette.text.primary}}>Name</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
style={{
|
style={{
|
||||||
@@ -456,7 +463,8 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
maxWidth: 434,
|
maxWidth: 434,
|
||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
marginRight: "15px",
|
marginRight: "15px",
|
||||||
backgroundColor: isEditOrgTab ? "#212121" : theme.palette.inputColor,
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
@@ -510,10 +518,11 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
height: "35px",
|
height: "35px",
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
},
|
},
|
||||||
classes: {
|
classes: {
|
||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
@@ -523,10 +532,10 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
{userdata?.support ? (
|
{userdata?.support ? (
|
||||||
<div style={{ alignItems: 'center' }}>
|
<div style={{ alignItems: 'center' }}>
|
||||||
<div style={{ marginRight: '12px', color: 'white' }}>Status</div>
|
<div style={{ marginRight: '12px', color: theme.palette.text.primary }}>Status</div>
|
||||||
<FormControl style={{ width: 220, height: 35 }}>
|
<FormControl style={{ width: 220, height: 35 }}>
|
||||||
<Select
|
<Select
|
||||||
style={{ minWidth: 220, marginTop: 5, maxWidth: 220, height: 35, borderRadius: 4 }}
|
style={{ minWidth: 220, marginTop: 5, maxWidth: 220, height: 35, borderRadius: 4, color: theme.palette.textFieldStyle.color}}
|
||||||
id="multiselect-status"
|
id="multiselect-status"
|
||||||
multiple
|
multiple
|
||||||
value={selectedStatus}
|
value={selectedStatus}
|
||||||
@@ -535,7 +544,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
renderValue={(selected) => selected.join(', ')}
|
renderValue={(selected) => selected.join(', ')}
|
||||||
MenuProps={MenuProps}
|
MenuProps={MenuProps}
|
||||||
>
|
>
|
||||||
{["contacted", "lead", "demo done", "pov", "customer", "open source", "student", "internal", "creator", "tech partner", "old customer", "old lead"].map((name) => (
|
{["contacted", "lead", "demo done", "pov", "customer", "open source", "student", "internal", "creator", "tech partner", "integration partner", "distribution partner", "service partner", "old customer", "old lead"].map((name) => (
|
||||||
<MenuItem key={name} value={name}>
|
<MenuItem key={name} value={name}>
|
||||||
<Checkbox checked={selectedStatus.indexOf(name) > -1} />
|
<Checkbox checked={selectedStatus.indexOf(name) > -1} />
|
||||||
<ListItemText primary={name} />
|
<ListItemText primary={name} />
|
||||||
@@ -549,13 +558,13 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
|
|
||||||
{isCloud ? (
|
{isCloud ? (
|
||||||
<div style={{ marginLeft: 13, fontSize: 16, color: "#9E9E9E" }} >
|
<div style={{ marginLeft: 13, fontSize: 16, color: "#9E9E9E" }} >
|
||||||
Change Region
|
<Typography variant="text" style={{color: theme.palette.text.primary}}>Change Region</Typography>
|
||||||
<RegionChangeModal selectedOrganization={selectedOrganization} setSelectedRegion={setSelectedRegion} userdata={userdata} handleSendChangeRegionMail={handleSendChangeRegionMail} />
|
<RegionChangeModal selectedOrganization={selectedOrganization} setSelectedRegion={setSelectedRegion} userdata={userdata} handleSendChangeRegionMail={handleSendChangeRegionMail} />
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: "10px" }} />
|
<div style={{ marginTop: "10px" }} />
|
||||||
About
|
<Typography variant="text" style={{color: theme.palette.text.primary}}>Description</Typography>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
@@ -565,7 +574,8 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
flex: "1",
|
flex: "1",
|
||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
marginRight: "15px",
|
marginRight: "15px",
|
||||||
backgroundColor: isEditOrgTab ? "#212121" : theme.palette.inputColor,
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
height: 89,
|
height: 89,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
}}
|
}}
|
||||||
@@ -618,7 +628,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
height: 89,
|
height: 89,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
@@ -629,7 +639,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="h5" style={{ color: "rgba(241, 241, 241, 1)", fontSize: 24, fontWeight: 600, marginTop: 40, textAlign: "left" }}>
|
<Typography variant="h5" style={{ fontSize: 24, fontWeight: 500, marginTop: 40, textAlign: "left" }}>
|
||||||
Preferences
|
Preferences
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -650,7 +660,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<span>
|
<span>
|
||||||
<Typography style={{ fontWeight: 400, fontSize: 16 }}>Org Documentation reference</Typography>
|
<Typography style={{ fontWeight: 400, fontSize: 18, color: theme.palette.text.primary }}>Org Documentation reference</Typography>
|
||||||
|
|
||||||
<Typography variant="body2" color="textSecondary" style={{ fontWeight: 400, fontSize: 16, marginTop: 8 }}>
|
<Typography variant="body2" color="textSecondary" style={{ fontWeight: 400, fontSize: 16, marginTop: 8 }}>
|
||||||
Add a URL that is added as a link, pointing to any external documentation page you want.
|
Add a URL that is added as a link, pointing to any external documentation page you want.
|
||||||
@@ -665,7 +675,8 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
height: 35,
|
height: 35,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
type="name"
|
type="name"
|
||||||
@@ -706,6 +717,13 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
auto_provision: selectedOrganization?.sso_config?.auto_provision,
|
auto_provision: selectedOrganization?.sso_config?.auto_provision,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (userdata.org_status.includes("integration_partner")) {
|
||||||
|
toast.info("Reloading page to update the changes everywhere")
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload()
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -716,8 +734,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
@@ -733,9 +750,9 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
serverside={false}
|
serverside={false}
|
||||||
/>
|
/>
|
||||||
<Grid item xs={12} style={{ marginTop: 20, }}>
|
<Grid item xs={12} style={{ marginTop: 20, }}>
|
||||||
<Typography variant="h4" style={{ textAlign: "left", color: "rgba(241, 241, 241, 1)", fontSize: 24, fontWeight: 600, }}>Workflow Backup Repository</Typography>
|
<Typography variant="h5" style={{ textAlign: "left", fontWeight: 500, }}>Workflow Backup Repository</Typography>
|
||||||
<Typography variant="body2" style={{ textAlign: "left", marginTop: 8, color: "#9E9E9E", fontSize: 16, fontWeight: 400 }}>
|
<Typography variant="body2" style={{ textAlign: "left", marginTop: 8, color: theme.palette.text.secondary, fontSize: 16, fontWeight: 400 }}>
|
||||||
Decide where workflows are backed up in a Git repository. Will create logs and notifications if upload fails. The repository and branch must already have been initialized. Files will show up in the repo root in the /orgId/workflow-status/workflowId.json format. <b>MSSP:</b> If suborg exists, this will automatically be applied for them as well (not retroactive). <a href="/docs/configuration#environment-variables" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">Credentials are encrypted.</a>
|
Decide where workflows are backed up in a Git repository. Will create logs and notifications if upload fails. The repository and branch must already have been initialized. Files will show up in the repo root in the /orgId/workflow-status/workflowId.json format. <b>MSSP:</b> If suborg exists, this will automatically be applied for them as well (not retroactive). <a href="/docs/configuration#environment-variables" style={{ textDecoration: "none", color: theme.palette.linkColor }} target="_blank">Credentials are encrypted.</a>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container style={{ marginTop: 10, }} spacing={2}>
|
<Grid container style={{ marginTop: 10, }} spacing={2}>
|
||||||
<Grid item xs={6} style={{}}>
|
<Grid item xs={6} style={{}}>
|
||||||
@@ -748,7 +765,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
marginRight: "16px",
|
marginRight: "16px",
|
||||||
height: 35,
|
height: 35,
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
type="name"
|
type="name"
|
||||||
@@ -767,7 +784,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -788,7 +805,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
marginRight: "16px",
|
marginRight: "16px",
|
||||||
height: 35,
|
height: 35,
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
type="name"
|
type="name"
|
||||||
@@ -807,7 +824,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -830,7 +847,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
marginRight: "16px",
|
marginRight: "16px",
|
||||||
height: 35,
|
height: 35,
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
type="name"
|
type="name"
|
||||||
@@ -849,8 +866,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
@@ -862,7 +878,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6} style={{}}>
|
<Grid item xs={6} style={{}}>
|
||||||
<span>
|
<span>
|
||||||
<Typography style={{ fontWeight: 400, fontSize: 16 }}>Git token/password</Typography>
|
<Typography style={{ fontWeight: 400, fontSize: 16 }}>New Git token/password</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
style={{
|
style={{
|
||||||
@@ -870,7 +886,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
marginRight: "16px",
|
marginRight: "16px",
|
||||||
height: 35,
|
height: 35,
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
id="outlined-with-placeholder"
|
id="outlined-with-placeholder"
|
||||||
@@ -888,7 +904,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -915,7 +931,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
marginRight: "16px",
|
marginRight: "16px",
|
||||||
height: 35,
|
height: 35,
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
type="name"
|
type="name"
|
||||||
@@ -932,7 +948,8 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -954,7 +971,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
flex: "1",
|
flex: "1",
|
||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
marginRight: "15px",
|
marginRight: "15px",
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
height: 35,
|
height: 35,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
@@ -972,7 +989,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -994,7 +1011,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
flex: "1",
|
flex: "1",
|
||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
marginRight: "15px",
|
marginRight: "15px",
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
height: 35,
|
height: 35,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
@@ -1012,7 +1029,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -1034,7 +1051,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
flex: "1",
|
flex: "1",
|
||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
marginRight: "15px",
|
marginRight: "15px",
|
||||||
backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor,
|
backgroundColor: isEditOrgTab ? theme.palette.textFieldStyle.backgroundColor : theme.palette.inputColor,
|
||||||
height: 35,
|
height: 35,
|
||||||
}}
|
}}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
@@ -1052,7 +1069,7 @@ const OrgHeaderexpandedNew = (props) => {
|
|||||||
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -1091,6 +1108,7 @@ const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userd
|
|||||||
"EU-2": "eu",
|
"EU-2": "eu",
|
||||||
"CA": "ca",
|
"CA": "ca",
|
||||||
"UK": "gb",
|
"UK": "gb",
|
||||||
|
"AUS": "au",
|
||||||
};
|
};
|
||||||
|
|
||||||
//let regiontag = "UK";
|
//let regiontag = "UK";
|
||||||
@@ -1112,6 +1130,9 @@ const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userd
|
|||||||
} else if (regiontag === "ca") {
|
} else if (regiontag === "ca") {
|
||||||
regiontag = "CA";
|
regiontag = "CA";
|
||||||
regionCode = "ca";
|
regionCode = "ca";
|
||||||
|
} else if (regiontag === "au") {
|
||||||
|
regiontag = "AUS";
|
||||||
|
regionCode = "au"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1124,11 +1145,12 @@ const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userd
|
|||||||
value={regiontag}
|
value={regiontag}
|
||||||
style={{ minWidth: 120, height: 35, borderRadius: 4 }}
|
style={{ minWidth: 120, height: 35, borderRadius: 4 }}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (userdata?.support) {
|
// if (userdata?.support) {
|
||||||
setSelectedRegion(e.target.value)
|
// setSelectedRegion(e.target.value)
|
||||||
} else {
|
// } else {
|
||||||
handleSendChangeRegionMail(e.target.value)
|
// handleSendChangeRegionMail(e.target.value)
|
||||||
}
|
// }
|
||||||
|
setSelectedRegion(e.target.value)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Object.keys(regionMapping).map((region, index) => {
|
{Object.keys(regionMapping).map((region, index) => {
|
||||||
@@ -1138,6 +1160,7 @@ const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userd
|
|||||||
selectedOrganization.region = "europe-west2";
|
selectedOrganization.region = "europe-west2";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if the current region matches the selected region
|
// Check if the current region matches the selected region
|
||||||
if (region === selectedOrganization.region) {
|
if (region === selectedOrganization.region) {
|
||||||
// If the region matches, set the MenuItem as selected
|
// If the region matches, set the MenuItem as selected
|
||||||
@@ -1145,7 +1168,7 @@ const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userd
|
|||||||
<MenuItem value={region} key={index} disabled>
|
<MenuItem value={region} key={index} disabled>
|
||||||
{/* show region image through cdn */}
|
{/* show region image through cdn */}
|
||||||
<img src={`https://flagcdn.com/48x36/${regionImageCode}.png`} alt={region} style={{ marginRight: 10 }} />
|
<img src={`https://flagcdn.com/48x36/${regionImageCode}.png`} alt={region} style={{ marginRight: 10 }} />
|
||||||
{region}
|
{region === "AUS" ? "AUS (test)" : region}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -1155,7 +1178,7 @@ const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userd
|
|||||||
alt={region}
|
alt={region}
|
||||||
style={{ marginRight: 10, width: 20, height: 18, }}
|
style={{ marginRight: 10, width: 20, height: 18, }}
|
||||||
/>
|
/>
|
||||||
{region}
|
{region === "AUS" ? "AUS (test)" : region}
|
||||||
</MenuItem>;
|
</MenuItem>;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import React, { useEffect, useState, useCallback, useContext } from 'react';
|
||||||
import { Link, useNavigate, useLocation } from "react-router-dom";
|
import { Link, useNavigate, useLocation } from "react-router-dom";
|
||||||
import Billing from "../components/Billing.jsx";
|
import Billing from "../components/Billing.jsx";
|
||||||
import Priorities from "../components/Priorities.jsx";
|
import Priorities from "../components/Priorities.jsx";
|
||||||
import Branding from "../components/Branding.jsx";
|
import Branding from "../components/Branding.jsx";
|
||||||
import AnalyticsTab from '../components/AnalyticsTab.jsx';
|
|
||||||
import EditOrgTab from '../components/EditOrgTab.jsx';
|
import EditOrgTab from '../components/EditOrgTab.jsx';
|
||||||
import CloudSyncTab from '../components/CloudSyncTab.jsx';
|
import CloudSyncTab from '../components/CloudSyncTab.jsx';
|
||||||
import SSOTab from "../components/ssoTab.jsx"
|
import SSOTab from "../components/ssoTab.jsx"
|
||||||
import { ToastContainer, toast } from "react-toastify";
|
import { ToastContainer, toast } from "react-toastify";
|
||||||
import { Button, Tooltip } from '@mui/material';
|
import { Button, Tooltip } from '@mui/material';
|
||||||
|
import { getTheme } from '../theme.jsx';
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
const OrganizationTab = (props) => {
|
const OrganizationTab = (props) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -26,7 +26,9 @@ const OrganizationTab = (props) => {
|
|||||||
selectedOrganization, handleGetOrg,
|
selectedOrganization, handleGetOrg,
|
||||||
handleStatusChange, handleEditOrg,
|
handleStatusChange, handleEditOrg,
|
||||||
isLoaded,
|
isLoaded,
|
||||||
removeCookie
|
removeCookie,
|
||||||
|
isIntegrationPartner, isChildOrg,
|
||||||
|
isGlobalUser
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [selectedTab, setSelectedTab] = useState('org_config');
|
const [selectedTab, setSelectedTab] = useState('org_config');
|
||||||
@@ -34,10 +36,28 @@ const OrganizationTab = (props) => {
|
|||||||
const [billingInfo, setBillingInfo] = useState({});
|
const [billingInfo, setBillingInfo] = useState({});
|
||||||
const [orgRequest, setOrgRequest] = React.useState(true);
|
const [orgRequest, setOrgRequest] = React.useState(true);
|
||||||
const [curIndex, setCurIndex] = React.useState(0);
|
const [curIndex, setCurIndex] = React.useState(0);
|
||||||
|
const items = ['Org Configuration', "SSO", "Notifications", 'Billing & Stats', 'Branding'];
|
||||||
|
const [visibleTabs, setVisibleTabs] = useState(items);
|
||||||
const [unreadNotifications, setUnreadNotifications] = React.useState(
|
const [unreadNotifications, setUnreadNotifications] = React.useState(
|
||||||
notifications?.filter((notification) => notification.read === false)?.length
|
notifications?.filter((notification) => notification.read === false)?.length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { themeMode, brandColor, brandName } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isIntegrationPartner && isChildOrg && !isGlobalUser) {
|
||||||
|
setVisibleTabs(items.filter((item) => item !== 'Branding' && item !== 'SSO'));
|
||||||
|
}else {
|
||||||
|
if (userdata && userdata.active_org && userdata.active_org.role === 'admin') {
|
||||||
|
setVisibleTabs(items);
|
||||||
|
}else {
|
||||||
|
setVisibleTabs(items.filter((item) => item !== 'SSO'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},[isIntegrationPartner, isChildOrg, isGlobalUser, userdata]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
const tabName = queryParams.get('admin_tab');
|
const tabName = queryParams.get('admin_tab');
|
||||||
@@ -49,10 +69,26 @@ const OrganizationTab = (props) => {
|
|||||||
} else if(decodedTabName === 'sso'){
|
} else if(decodedTabName === 'sso'){
|
||||||
setCurIndex(1)
|
setCurIndex(1)
|
||||||
}else if (decodedTabName === 'notifications' || decodedTabName === 'priorities') {
|
}else if (decodedTabName === 'notifications' || decodedTabName === 'priorities') {
|
||||||
setCurIndex(2);
|
if (isIntegrationPartner && isChildOrg && !isGlobalUser) {
|
||||||
|
setCurIndex(1);
|
||||||
|
}else {
|
||||||
|
if (userdata && userdata.active_org && userdata.active_org.role === 'admin') {
|
||||||
|
setCurIndex(2);
|
||||||
|
}else {
|
||||||
|
setCurIndex(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (decodedTabName === 'billingstats' || decodedTabName === 'billing') {
|
} else if (decodedTabName === 'billingstats' || decodedTabName === 'billing') {
|
||||||
setCurIndex(3);
|
if (isIntegrationPartner && isChildOrg && !isGlobalUser) {
|
||||||
} else if (decodedTabName === 'branding(beta)') {
|
setCurIndex(2);
|
||||||
|
} else {
|
||||||
|
if (userdata && userdata?.active_org && userdata?.active_org?.role === 'admin') {
|
||||||
|
setCurIndex(3);
|
||||||
|
} else {
|
||||||
|
setCurIndex(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (decodedTabName === 'branding') {
|
||||||
setCurIndex(4);
|
setCurIndex(4);
|
||||||
}
|
}
|
||||||
// else if (decodedTabName === 'analytics') {
|
// else if (decodedTabName === 'analytics') {
|
||||||
@@ -65,7 +101,7 @@ const OrganizationTab = (props) => {
|
|||||||
const formattedTabName = tabName.toLowerCase().replace(/[\s&]+/g, '');
|
const formattedTabName = tabName.toLowerCase().replace(/[\s&]+/g, '');
|
||||||
const encodedTabName = encodeURIComponent(formattedTabName);
|
const encodedTabName = encodeURIComponent(formattedTabName);
|
||||||
setSelectedTab(formattedTabName);
|
setSelectedTab(formattedTabName);
|
||||||
document.title = `Shuffle - admin - ${formattedTabName}`;
|
document.title = brandName?.length > 0 ? `${brandName} - admin - ${formattedTabName}` : `Shuffle - admin - ${formattedTabName}`;
|
||||||
navigate(`?admin_tab=${encodedTabName}`);
|
navigate(`?admin_tab=${encodedTabName}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -121,7 +157,7 @@ const OrganizationTab = (props) => {
|
|||||||
isLoaded={isLoaded}
|
isLoaded={isLoaded}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'branding(beta)':
|
case 'branding':
|
||||||
return <Branding
|
return <Branding
|
||||||
isCloud={isCloud}
|
isCloud={isCloud}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
@@ -138,10 +174,11 @@ const OrganizationTab = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", width: "100%", color: '#FFFFFF', backgroundColor: '#212121', borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", boxSizing: 'border-box' }}>
|
<div style={{ height: "100%", width: "100%", color: theme.palette.platformColor, backgroundColor: theme.palette.platformColor, borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: theme.palette.defaultBorder, boxSizing: 'border-box' }}>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-around', width: "100%", borderBottom: '1px solid #494949' ,boxSizing: 'border-box' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-around', width: "100%", borderBottom: theme.palette.defaultBorder ,boxSizing: 'border-box' }}>
|
||||||
{['Org Configuration', "sso", "Notifications", 'Billing & Stats', 'Branding (Beta)'].map((tabName, index) => (
|
{visibleTabs.map((tabName, index) => (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
key={index}
|
key={index}
|
||||||
title={
|
title={
|
||||||
@@ -162,10 +199,10 @@ const OrganizationTab = (props) => {
|
|||||||
sx={{
|
sx={{
|
||||||
"&.MuiButton-root": {
|
"&.MuiButton-root": {
|
||||||
padding: '28px 0',
|
padding: '28px 0',
|
||||||
borderBottom: index === curIndex ? '2px solid #FF8444' : 'none',
|
borderBottom: index === curIndex ? `2px solid ${theme.palette.primary.main}`: 'none',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontWeight: index === curIndex ? 'bold' : 'normal',
|
fontWeight: index === curIndex ? 'bold' : 'normal',
|
||||||
color: index === curIndex ? "#FF8444" : "#FFFFFF",
|
color: index === curIndex ? theme.palette.primary.main : theme.palette.text.primary,
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -173,7 +210,7 @@ const OrganizationTab = (props) => {
|
|||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
},
|
},
|
||||||
"&: hover": {
|
"&: hover": {
|
||||||
backgroundColor: "#323232"
|
backgroundColor: theme.palette.hoverColor
|
||||||
},
|
},
|
||||||
"&.Mui-disabled": {
|
"&.Mui-disabled": {
|
||||||
color: "#6F6F6F",
|
color: "#6F6F6F",
|
||||||
@@ -183,7 +220,7 @@ const OrganizationTab = (props) => {
|
|||||||
((tabName === "sso")) && !(userdata?.support || userdata?.active_org?.role === "admin")
|
((tabName === "sso")) && !(userdata?.support || userdata?.active_org?.role === "admin")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{index === 2 && unreadNotifications > 0 ? (
|
{tabName.toLowerCase() === "notifications" && unreadNotifications > 0 ? (
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -192,7 +229,7 @@ const OrganizationTab = (props) => {
|
|||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
backgroundColor: '#FF8444',
|
backgroundColor: theme.palette.primary.main,
|
||||||
color: '#FFFFFF',
|
color: '#FFFFFF',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -204,7 +241,7 @@ const OrganizationTab = (props) => {
|
|||||||
{tabName}
|
{tabName}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>{index === 1 ? "SSO" : tabName}</>
|
<>{tabName}</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Box, Typography } from '@mui/material'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const PartnerApps = () => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
minHeight: "500px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>Partner Apps</Typography>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PartnerApps
|
||||||
@@ -0,0 +1,987 @@
|
|||||||
|
import React, { memo, useEffect, useState, useContext } from "react";
|
||||||
|
|
||||||
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import { getTheme } from "../theme.jsx";
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
import countries from "./Countries.jsx";
|
||||||
|
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Paper,
|
||||||
|
OutlinedInput,
|
||||||
|
Checkbox,
|
||||||
|
Card,
|
||||||
|
Tooltip,
|
||||||
|
FormControlLabel,
|
||||||
|
Chip,
|
||||||
|
Link,
|
||||||
|
Typography,
|
||||||
|
Switch,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
Divider,
|
||||||
|
ListItemText,
|
||||||
|
TextField,
|
||||||
|
Button,
|
||||||
|
Tabs,
|
||||||
|
Tab,
|
||||||
|
Grid,
|
||||||
|
Autocomplete,
|
||||||
|
Skeleton,
|
||||||
|
Box,
|
||||||
|
} from "@mui/material";
|
||||||
|
const useStyles = makeStyles({
|
||||||
|
notchedOutline: {
|
||||||
|
borderColor: "#f85a3e !important",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const PartnerDetails = (props) => {
|
||||||
|
const {
|
||||||
|
userdata,
|
||||||
|
selectedOrganization,
|
||||||
|
setSelectedOrganization,
|
||||||
|
globalUrl,
|
||||||
|
isCloud,
|
||||||
|
adminTab,
|
||||||
|
isEditOrgTab,
|
||||||
|
partnerData,
|
||||||
|
loadingPartnerData,
|
||||||
|
setPartnerData,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles();
|
||||||
|
const defaultBranch = "main";
|
||||||
|
const ITEM_HEIGHT = 48;
|
||||||
|
const ITEM_PADDING_TOP = 8;
|
||||||
|
const MenuProps = {
|
||||||
|
PaperProps: {
|
||||||
|
style: {
|
||||||
|
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
||||||
|
width: 400,
|
||||||
|
borderRadius: 10,
|
||||||
|
overflowY: "scroll",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getContentAnchorEl: () => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const expertiseOptions = [
|
||||||
|
"Cybersecurity",
|
||||||
|
"Cloud Security",
|
||||||
|
"Managed Detection and Response (MDR)",
|
||||||
|
"Incident Response",
|
||||||
|
"Penetration Testing",
|
||||||
|
"Compliance and Governance",
|
||||||
|
"Network Security",
|
||||||
|
"Endpoint Security",
|
||||||
|
"Identity and Access Management (IAM)",
|
||||||
|
"SIEM",
|
||||||
|
];
|
||||||
|
const servicesOptions = [
|
||||||
|
"Cybersecurity Consulting",
|
||||||
|
"Managed Security",
|
||||||
|
"Incident Response",
|
||||||
|
"Penetration Testing",
|
||||||
|
"Cloud Security",
|
||||||
|
"Managed Detection",
|
||||||
|
"Endpoint Security",
|
||||||
|
"Network Security",
|
||||||
|
"Identity Management",
|
||||||
|
"Compliance",
|
||||||
|
"Security Training",
|
||||||
|
"Security Management",
|
||||||
|
"Threat Intelligence",
|
||||||
|
"Web Security",
|
||||||
|
"Database Security",
|
||||||
|
"Disaster Recovery",
|
||||||
|
"IT Security Audit",
|
||||||
|
"Cybersecurity Training",
|
||||||
|
"Security Automation",
|
||||||
|
"AI Security",
|
||||||
|
"IoT Security",
|
||||||
|
"Cloud Security Broker",
|
||||||
|
"Security Service",
|
||||||
|
"Managed Security Provider",
|
||||||
|
"Cybersecurity Service",
|
||||||
|
]
|
||||||
|
|
||||||
|
const solutionsOptions = [
|
||||||
|
"EDR",
|
||||||
|
"MDR",
|
||||||
|
"XDR",
|
||||||
|
"Case Management",
|
||||||
|
"SIEM",
|
||||||
|
"Vulnerability Management",
|
||||||
|
"IPS",
|
||||||
|
"IDS",
|
||||||
|
"Threat Intelligence",
|
||||||
|
"IAM",
|
||||||
|
"Data Security",
|
||||||
|
"Incident Response",
|
||||||
|
"Cloud Security",
|
||||||
|
"Network Security",
|
||||||
|
]
|
||||||
|
|
||||||
|
const { themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
const [isDisabled, setIsDisabled] = useState(isCloud ? userdata?.active_org?.is_partner ? false : true : true);
|
||||||
|
const handleExpertiseChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
expertise: value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsDisabled(isCloud ? userdata?.active_org?.is_partner ? false : true : true);
|
||||||
|
if(userdata?.support) {
|
||||||
|
setIsDisabled(false);
|
||||||
|
}
|
||||||
|
}, [userdata, isCloud]);
|
||||||
|
|
||||||
|
const handleServicesChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
services: Array.isArray(value) ? value : [],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSolutionsChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
solutions: Array.isArray(value) ? value : [],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSelectedRegion = (region) => {
|
||||||
|
// send a POST request to /api/v1/orgs/{org_id}/region with the region as the body
|
||||||
|
const regionMap = {
|
||||||
|
US: "us-west2",
|
||||||
|
EU: "europe-west2",
|
||||||
|
CA: "northamerica-northeast1",
|
||||||
|
UK: "europe-west2",
|
||||||
|
"EU-2": "europe-west3",
|
||||||
|
AUS: "australia-southeast1",
|
||||||
|
};
|
||||||
|
|
||||||
|
region = regionMap[region] || region;
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
dst_region: region,
|
||||||
|
};
|
||||||
|
|
||||||
|
toast.info(
|
||||||
|
"Changing region to " + region + "...This may take a few minutes."
|
||||||
|
);
|
||||||
|
|
||||||
|
fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/change/region`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
timeOut: 1000,
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
response
|
||||||
|
.json()
|
||||||
|
.then((reason) => {
|
||||||
|
toast.error("Failed to change region: " + reason.reason);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error("Failed to change region");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast("Region changed successfully! Reloading in 5 seconds..");
|
||||||
|
// Reload the page in 2 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return responseJson
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loadingPartnerData) {
|
||||||
|
return (
|
||||||
|
<div style={{ textAlign: "left", maxWidth: "95%" }}>
|
||||||
|
<Grid container spacing={3} style={{ textAlign: "left", marginTop: 5 }}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<span>
|
||||||
|
<div>
|
||||||
|
<div style={{ flex: "3", color: "white" }}>
|
||||||
|
<div style={{ marginTop: 8, display: "flex" }} />
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<div style={{ width: "100%", maxWidth: 434, marginRight: 10 }}>
|
||||||
|
<Typography variant="text" style={{ color: theme?.palette?.text?.primary }}>
|
||||||
|
Name
|
||||||
|
</Typography>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width="100%"
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* <div style={{ alignItems: "center" }}>
|
||||||
|
<div style={{ marginRight: "12px", color: theme?.palette?.text?.primary }}>
|
||||||
|
Expertise
|
||||||
|
</div>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width={220}
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ alignItems: "center", marginLeft: 12 }}>
|
||||||
|
<div style={{ marginRight: "12px", color: theme?.palette?.text?.primary }}>
|
||||||
|
Services
|
||||||
|
</div>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width={220}
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div> */}
|
||||||
|
<div style={{ alignItems: "center" }}>
|
||||||
|
<div style={{ marginRight: "12px", color: theme?.palette?.text?.primary }}>
|
||||||
|
Solutions
|
||||||
|
</div>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width={220}
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ marginLeft: 13, fontSize: 16, color: "#9E9E9E" }}>
|
||||||
|
<Typography variant="text" style={{ color: theme?.palette?.text?.primary }}>
|
||||||
|
Region
|
||||||
|
</Typography>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width={190}
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ alignItems: "center", marginLeft: 12 }}>
|
||||||
|
<div style={{ marginRight: "12px", color: theme?.palette?.text?.primary }}>
|
||||||
|
Country
|
||||||
|
</div>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width={220}
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: "10px" }}>
|
||||||
|
<Typography variant="text" style={{ color: theme?.palette?.text?.primary }}>
|
||||||
|
Description
|
||||||
|
</Typography>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={89}
|
||||||
|
width="100%"
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style={{ width: "100%", maxWidth: 500, marginRight: 10, marginTop: 10 }}>
|
||||||
|
<Typography variant="text" style={{ color: theme?.palette?.text?.primary }}>
|
||||||
|
Website URL
|
||||||
|
</Typography>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width="100%"
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ width: "100%", maxWidth: 500, marginRight: 10, marginTop: 20 }}>
|
||||||
|
<Typography variant="text" style={{ color: theme?.palette?.text?.primary }}>
|
||||||
|
Article URL
|
||||||
|
</Typography>
|
||||||
|
<Skeleton
|
||||||
|
variant="rounded"
|
||||||
|
height={35}
|
||||||
|
width="100%"
|
||||||
|
style={{
|
||||||
|
marginTop: 5,
|
||||||
|
borderRadius: 4
|
||||||
|
}}
|
||||||
|
animation="wave"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ textAlign: "left", maxWidth: "95%" }}>
|
||||||
|
<Grid container spacing={3} style={{ textAlign: "left", marginTop: 5 }}>
|
||||||
|
<Grid item xs={12} style={{}}>
|
||||||
|
<span>
|
||||||
|
<div style={{}}>
|
||||||
|
<div style={{ flex: "3", color: "white" }}>
|
||||||
|
<div style={{ marginTop: 8, display: "flex" }} />
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<div
|
||||||
|
style={{ width: "100%", maxWidth: 434, marginRight: 10 }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="text"
|
||||||
|
style={{ color: theme.palette.text.primary }}
|
||||||
|
>
|
||||||
|
Name
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
disabled={isDisabled}
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
height: 35,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 434,
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab
|
||||||
|
? theme.palette.textFieldStyle.backgroundColor
|
||||||
|
: theme.palette.inputColor,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="Name"
|
||||||
|
type="name"
|
||||||
|
id="standard-required"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
value={partnerData?.name}
|
||||||
|
onBlur={() => {}}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 100) {
|
||||||
|
toast("Choose a shorter name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
name: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: "35px",
|
||||||
|
fontSize: "1em",
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor:
|
||||||
|
theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
},
|
||||||
|
classes: {
|
||||||
|
notchedOutline: isEditOrgTab
|
||||||
|
? null
|
||||||
|
: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* <div style={{ alignItems: "center" }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginRight: "12px",
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Expertise
|
||||||
|
</div>
|
||||||
|
<FormControl style={{ width: 220, height: 35 }}>
|
||||||
|
<Select
|
||||||
|
style={{
|
||||||
|
minWidth: 220,
|
||||||
|
marginTop: 5,
|
||||||
|
maxWidth: 220,
|
||||||
|
height: 35,
|
||||||
|
borderRadius: 4,
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
disabled={isDisabled}
|
||||||
|
id="multiselect-status"
|
||||||
|
multiple
|
||||||
|
value={partnerData?.expertise}
|
||||||
|
onChange={(event) => {
|
||||||
|
handleExpertiseChange(event);
|
||||||
|
}}
|
||||||
|
input={<OutlinedInput />}
|
||||||
|
renderValue={(selected) => selected.join(", ")}
|
||||||
|
MenuProps={MenuProps}
|
||||||
|
>
|
||||||
|
{expertiseOptions?.map((name) => (
|
||||||
|
<MenuItem key={name} value={name}>
|
||||||
|
<Checkbox
|
||||||
|
checked={partnerData?.expertise?.indexOf(name) > -1}
|
||||||
|
/>
|
||||||
|
<ListItemText primary={name} />
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
<div style={{ alignItems: "center", marginLeft: 12 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginRight: "12px",
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Services
|
||||||
|
</div>
|
||||||
|
<FormControl style={{ width: 220, height: 35 }}>
|
||||||
|
<Select
|
||||||
|
style={{
|
||||||
|
minWidth: 220,
|
||||||
|
marginTop: 5,
|
||||||
|
maxWidth: 220,
|
||||||
|
height: 35,
|
||||||
|
borderRadius: 4,
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
disabled={isDisabled}
|
||||||
|
id="multiselect-status"
|
||||||
|
multiple
|
||||||
|
value={partnerData?.services || []}
|
||||||
|
onChange={(event) => {
|
||||||
|
handleServicesChange(event);
|
||||||
|
}}
|
||||||
|
input={<OutlinedInput />}
|
||||||
|
renderValue={(selected) => selected.join(", ")}
|
||||||
|
MenuProps={MenuProps}
|
||||||
|
>
|
||||||
|
{servicesOptions?.map((name) => (
|
||||||
|
<MenuItem key={name} value={name}>
|
||||||
|
<Checkbox
|
||||||
|
checked={(partnerData?.services || []).indexOf(name) > -1}
|
||||||
|
/>
|
||||||
|
<ListItemText primary={name} />
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div> */}
|
||||||
|
<div style={{ alignItems: "center" }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginRight: "12px",
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Solutions
|
||||||
|
</div>
|
||||||
|
<FormControl style={{ width: 190, height: 35 }}>
|
||||||
|
<Select
|
||||||
|
style={{
|
||||||
|
minWidth: 190,
|
||||||
|
marginTop: 5,
|
||||||
|
maxWidth: 190,
|
||||||
|
height: 35,
|
||||||
|
borderRadius: 4,
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
disabled={isDisabled}
|
||||||
|
id="multiselect-status"
|
||||||
|
multiple
|
||||||
|
value={partnerData?.solutions || []}
|
||||||
|
onChange={(event) => {
|
||||||
|
handleSolutionsChange(event);
|
||||||
|
}}
|
||||||
|
input={<OutlinedInput />}
|
||||||
|
renderValue={(selected) => selected.join(", ")}
|
||||||
|
MenuProps={MenuProps}
|
||||||
|
>
|
||||||
|
{solutionsOptions?.map((name) => (
|
||||||
|
<MenuItem key={name} value={name}>
|
||||||
|
<Checkbox
|
||||||
|
checked={(partnerData?.solutions || []).indexOf(name) > -1}
|
||||||
|
/>
|
||||||
|
<ListItemText primary={name} />
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{ marginLeft: 13, fontSize: 16, color: "#9E9E9E" }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="text"
|
||||||
|
style={{ color: theme.palette.text.primary }}
|
||||||
|
>
|
||||||
|
Region
|
||||||
|
</Typography>
|
||||||
|
<RegionChangeModal
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
selectedOrganization={selectedOrganization}
|
||||||
|
setSelectedRegion={setSelectedRegion}
|
||||||
|
partnerData={partnerData}
|
||||||
|
setPartnerData={setPartnerData}
|
||||||
|
userdata={userdata}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ alignItems: "flex-start", marginLeft: 13, display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography
|
||||||
|
variant="text"
|
||||||
|
style={{ color: theme.palette.text.primary }}
|
||||||
|
>
|
||||||
|
Country
|
||||||
|
</Typography>
|
||||||
|
<FormControl style={{ width: 210, height: 35 }}>
|
||||||
|
<Autocomplete
|
||||||
|
id="country-select"
|
||||||
|
value={countries.find(country => country.label === partnerData?.country)}
|
||||||
|
style={{
|
||||||
|
minWidth: 210,
|
||||||
|
marginTop: 5,
|
||||||
|
maxWidth: 210,
|
||||||
|
height: 35,
|
||||||
|
borderRadius: 4,
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
disabled={isDisabled}
|
||||||
|
options={countries}
|
||||||
|
autoHighlight
|
||||||
|
onClear={() => {
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
country: "",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
getOptionLabel={(option) => option?.label || ""}
|
||||||
|
onChange={(event, newValue) => {
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
country: newValue?.label,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
renderOption={(props, option) => (
|
||||||
|
<Box
|
||||||
|
component="li"
|
||||||
|
sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
loading="lazy"
|
||||||
|
width="20"
|
||||||
|
src={`https://flagcdn.com/48x36/${option.code.toLowerCase()}.png`}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
placeholder="Select country"
|
||||||
|
variant="outlined"
|
||||||
|
InputProps={{
|
||||||
|
...params.InputProps,
|
||||||
|
startAdornment: partnerData?.country ? (
|
||||||
|
<img
|
||||||
|
loading="lazy"
|
||||||
|
width="20"
|
||||||
|
src={`https://flagcdn.com/48x36/${countries.find(country => country.label === partnerData.country)?.code.toLowerCase()}.png`}
|
||||||
|
alt=""
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
/>
|
||||||
|
) : null,
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: "35px",
|
||||||
|
fontSize: "1em",
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
},
|
||||||
|
classes: {
|
||||||
|
notchedOutline: isEditOrgTab ? null : classes.notchedOutline,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: "10px", }} />
|
||||||
|
<Typography
|
||||||
|
variant="text"
|
||||||
|
style={{ color: theme.palette.text.primary }}
|
||||||
|
>
|
||||||
|
Description
|
||||||
|
</Typography>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
disabled={isDisabled}
|
||||||
|
multiline
|
||||||
|
rows={3}
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
marginTop: "5px",
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab
|
||||||
|
? theme.palette.textFieldStyle.backgroundColor
|
||||||
|
: theme.palette.inputColor,
|
||||||
|
height: 89,
|
||||||
|
borderRadius: 4,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
type="name"
|
||||||
|
id="outlined-with-placeholder"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
placeholder="A description for the organization"
|
||||||
|
value={partnerData?.description}
|
||||||
|
onBlur={(e) => {
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
description: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onChange={(e) => {
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
description: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
classes: {
|
||||||
|
notchedOutline: isEditOrgTab
|
||||||
|
? null
|
||||||
|
: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: 89,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
style={{ width: "100%", maxWidth: 500, marginRight: 10, marginTop: 10 }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="text"
|
||||||
|
style={{ color: theme.palette.text.primary }}
|
||||||
|
>
|
||||||
|
Website URL
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
disabled={isDisabled}
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
height: 35,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 500,
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab
|
||||||
|
? theme.palette.textFieldStyle.backgroundColor
|
||||||
|
: theme.palette.inputColor,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="https://www.example.com"
|
||||||
|
type="name"
|
||||||
|
id="standard-required"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
value={partnerData?.website_url}
|
||||||
|
onBlur={() => {}}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 100) {
|
||||||
|
toast("Choose a shorter website URL.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
website_url: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: "35px",
|
||||||
|
fontSize: "1em",
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor:
|
||||||
|
theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
},
|
||||||
|
classes: {
|
||||||
|
notchedOutline: isEditOrgTab
|
||||||
|
? null
|
||||||
|
: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{ width: "100%", maxWidth: 500, marginRight: 10, marginTop: 20 }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="text"
|
||||||
|
style={{ color: theme.palette.text.primary }}
|
||||||
|
>
|
||||||
|
Article URL
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
disabled={isDisabled}
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
height: 35,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 500,
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
backgroundColor: isEditOrgTab
|
||||||
|
? theme.palette.textFieldStyle.backgroundColor
|
||||||
|
: theme.palette.inputColor,
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="https://www.example.com"
|
||||||
|
type="name"
|
||||||
|
id="standard-required"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
value={partnerData?.article_url}
|
||||||
|
onBlur={() => {}}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 100) {
|
||||||
|
toast("Choose a shorter article URL.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
article_url: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
color: theme.palette.textFieldStyle.color,
|
||||||
|
height: "35px",
|
||||||
|
fontSize: "1em",
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor:
|
||||||
|
theme.palette.textFieldStyle.backgroundColor,
|
||||||
|
},
|
||||||
|
classes: {
|
||||||
|
notchedOutline: isEditOrgTab
|
||||||
|
? null
|
||||||
|
: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PartnerDetails;
|
||||||
|
|
||||||
|
const RegionChangeModal = memo(
|
||||||
|
({
|
||||||
|
isDisabled,
|
||||||
|
selectedOrganization,
|
||||||
|
setSelectedRegion,
|
||||||
|
userdata,
|
||||||
|
partnerData,
|
||||||
|
setPartnerData,
|
||||||
|
}) => {
|
||||||
|
// Show from options: "us-west2", "europe-west2", "europe-west3", "northamerica-northeast1"
|
||||||
|
// var regions = ["us-west2", "europe-west2", "europe-west3", "northamerica-northeast1"]
|
||||||
|
|
||||||
|
const regionMapping = {
|
||||||
|
"Africa": "af",
|
||||||
|
"Asia Pacific (APAC)": "",
|
||||||
|
"Europe": "eu",
|
||||||
|
"Latin America": "la",
|
||||||
|
"Middle East": "me",
|
||||||
|
"North America": "na",
|
||||||
|
"Global": ""
|
||||||
|
};
|
||||||
|
|
||||||
|
//let regiontag = "UK";
|
||||||
|
let regiontag = partnerData?.region || "UK";
|
||||||
|
let regionCode = "gb";
|
||||||
|
|
||||||
|
const regionsplit = selectedOrganization?.region_url?.split(".");
|
||||||
|
|
||||||
|
if (regionsplit?.length > 2 && !regionsplit[0]?.includes("shuffler")) {
|
||||||
|
const namesplit = regionsplit[0]?.split("/");
|
||||||
|
regiontag = namesplit[namesplit.length - 1];
|
||||||
|
|
||||||
|
if (regiontag === "california") {
|
||||||
|
regiontag = "US";
|
||||||
|
regionCode = "us";
|
||||||
|
} else if (regiontag === "frankfurt") {
|
||||||
|
regiontag = "EU-2";
|
||||||
|
regionCode = "eu";
|
||||||
|
} else if (regiontag === "ca") {
|
||||||
|
regiontag = "CA";
|
||||||
|
regionCode = "ca";
|
||||||
|
} else if (regiontag === "austrailia") {
|
||||||
|
regiontag = "AUS";
|
||||||
|
regionCode = "au";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
disabled={isDisabled}
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
marginTop: 5,
|
||||||
|
alignItems: "center",
|
||||||
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <InputLabel id="demo-simple-select-label">Region</InputLabel> */}
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={partnerData?.region || "Europe"}
|
||||||
|
style={{ minWidth: 190, height: 35, borderRadius: 4 }}
|
||||||
|
onChange={(e) => {
|
||||||
|
// if (userdata?.support) {
|
||||||
|
// setSelectedRegion(e.target.value)
|
||||||
|
// } else {
|
||||||
|
// handleSendChangeRegionMail(e.target.value)
|
||||||
|
// }
|
||||||
|
setPartnerData({
|
||||||
|
...partnerData,
|
||||||
|
region: e.target.value,
|
||||||
|
})
|
||||||
|
|
||||||
|
// setSelectedRegion(e.target.value)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Object.keys(regionMapping).map((region, index) => {
|
||||||
|
const regionImageCode = regionMapping[region];
|
||||||
|
// Set the default region if selectedOrganization.region is not set
|
||||||
|
if (selectedOrganization.region === undefined) {
|
||||||
|
selectedOrganization.region = "europe-west2";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region === "AUS") {
|
||||||
|
region = "AUS (test)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the current region matches the selected region
|
||||||
|
if (region === selectedOrganization.region) {
|
||||||
|
// If the region matches, set the MenuItem as selected
|
||||||
|
return (
|
||||||
|
<MenuItem value={region} key={index} disabled>
|
||||||
|
{/* show region image through cdn */}
|
||||||
|
{/* <img
|
||||||
|
src={`https://flagcdn.com/48x36/${regionImageCode}.png`}
|
||||||
|
alt={region}
|
||||||
|
style={{ marginRight: 10 }}
|
||||||
|
/> */}
|
||||||
|
{region}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<MenuItem sx={{ display: "flex" }} key={index} value={region}>
|
||||||
|
{/* <img
|
||||||
|
src={`https://flagcdn.com/48x36/${regionImageCode}.png`}
|
||||||
|
alt={region}
|
||||||
|
style={{ marginRight: 10, width: 20, height: 18 }}
|
||||||
|
/> */}
|
||||||
|
{region}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
import React, { useEffect, useState, useContext } from 'react';
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
import { getTheme } from '../theme.jsx';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
Box,
|
||||||
|
IconButton,
|
||||||
|
Tooltip,
|
||||||
|
} from "@mui/material";
|
||||||
|
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
||||||
|
import { useNavigate } from 'react-router';
|
||||||
|
import PartnerHeader from '../components/PartnerHeader.jsx';
|
||||||
|
import PartnerDetails from '../components/PartnerDetails.jsx';
|
||||||
|
|
||||||
|
const PartnerSettings = (props) => {
|
||||||
|
const {
|
||||||
|
isCloud,
|
||||||
|
userdata,
|
||||||
|
globalUrl,
|
||||||
|
serverside,
|
||||||
|
loadingPartnerData,
|
||||||
|
selectedOrganization,
|
||||||
|
setSelectedOrganization,
|
||||||
|
handleGetOrg,
|
||||||
|
partnerData,
|
||||||
|
setPartnerData,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const [isPartner, setIsPartner] = React.useState(isCloud ? userdata?.active_org?.is_partner ? true : false : false);
|
||||||
|
const [partnerTypes, setPartnerTypes] = React.useState({});
|
||||||
|
const [isPublishing, setIsPublishing] = React.useState(false);
|
||||||
|
const [isToggling, setIsToggling] = React.useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsPartner(isCloud ? userdata?.active_org?.is_partner ? true : false : false);
|
||||||
|
if(userdata?.support){
|
||||||
|
setIsPartner(true);
|
||||||
|
}
|
||||||
|
}, [userdata, isCloud]);
|
||||||
|
// Partner Types handling : Getting from org status
|
||||||
|
useEffect(() => {
|
||||||
|
const partnerTypes = {};
|
||||||
|
userdata?.org_status.forEach(status => {
|
||||||
|
if (status.includes("_partner")) {
|
||||||
|
partnerTypes[status] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setPartnerTypes(partnerTypes);
|
||||||
|
}, [selectedOrganization]);
|
||||||
|
// Partner Type Colors
|
||||||
|
const partnerTypeColors = {
|
||||||
|
"tech_partner": "#ff8544",
|
||||||
|
"distribution_partner": "#2BC07E",
|
||||||
|
"service_partner": "#a99cf9",
|
||||||
|
"integration_partner": "#fb47a0"
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSendUpdateRequest = () => {
|
||||||
|
toast("Your request has been sent to the support team. They will review your request and get back to you as soon as possible.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open partner page in new tab
|
||||||
|
const handleOpenPartnerPage = () => {
|
||||||
|
if (partnerData?.id) {
|
||||||
|
if(partnerData?.public){
|
||||||
|
window.open(`${window.location.origin}/partners/${partnerData.name.toLowerCase().replaceAll(" ", "_")}`)
|
||||||
|
}else{
|
||||||
|
window.open(`${window.location.origin}/partners/${partnerData?.id}`, "_blank");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast.error("Partner ID not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Partner Details
|
||||||
|
const handleUpdatePartnerDetails = () => {
|
||||||
|
// Validate required fields before publishing
|
||||||
|
const requiredStringFields = [
|
||||||
|
{ field: partnerData?.name, name: "Partner Name" },
|
||||||
|
{ field: partnerData?.description, name: "Description" },
|
||||||
|
{ field: selectedOrganization?.id, name: "Organization Id" },
|
||||||
|
{ field: partnerData?.image_url, name: "Logo Image" },
|
||||||
|
{ field: partnerData?.landscape_image_url, name: "Landscape Image" },
|
||||||
|
{ field: partnerData?.website_url, name: "Website URL" },
|
||||||
|
{ field: partnerData?.article_url, name: "Article URL" },
|
||||||
|
{ field: partnerData?.country, name: "Country" },
|
||||||
|
{ field: partnerData?.region, name: "Region" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Required array fields (multi-select dropdowns)
|
||||||
|
const requiredArrayFields = [
|
||||||
|
{ field: partnerData?.solutions, name: "Solutions" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Check if any required string fields are empty
|
||||||
|
const emptyStringFields = requiredStringFields.filter(item =>
|
||||||
|
!item.field || item.field.trim() === ""
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if any required array fields are empty
|
||||||
|
const emptyArrayFields = requiredArrayFields.filter(item =>
|
||||||
|
!item.field || !Array.isArray(item.field) || item.field.length === 0
|
||||||
|
);
|
||||||
|
|
||||||
|
// Combine all empty fields
|
||||||
|
const allEmptyFields = [...emptyStringFields, ...emptyArrayFields];
|
||||||
|
|
||||||
|
// If there are empty required fields, show error and return
|
||||||
|
if (allEmptyFields.length > 0) {
|
||||||
|
const missingFields = allEmptyFields.map(item => item.name).join(", ");
|
||||||
|
toast.error(`Please fill in all required fields: ${missingFields}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if at least one partner type is selected
|
||||||
|
if (Object.keys(partnerTypes).length === 0) {
|
||||||
|
toast.error("There should be at least one partner type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsPublishing(true);
|
||||||
|
const url = globalUrl + "/api/v1/partners/" + userdata?.active_org?.id;
|
||||||
|
const data = {
|
||||||
|
id: partnerData.id?.trim() || null,
|
||||||
|
name: partnerData.name?.trim(),
|
||||||
|
org_id: selectedOrganization?.id?.trim(),
|
||||||
|
description: partnerData.description?.trim(),
|
||||||
|
website_url: partnerData.website_url?.trim(),
|
||||||
|
article_url: partnerData.article_url?.trim(),
|
||||||
|
partner_type: partnerTypes,
|
||||||
|
expertise: partnerData?.expertise || [],
|
||||||
|
services: partnerData?.services || [],
|
||||||
|
solutions: partnerData?.solutions || [],
|
||||||
|
country: partnerData?.country || "",
|
||||||
|
region: partnerData?.region || "",
|
||||||
|
image_url: partnerData?.image_url?.trim(),
|
||||||
|
landscape_image_url: partnerData?.landscape_image_url?.trim(),
|
||||||
|
public: partnerData?.public
|
||||||
|
}
|
||||||
|
fetch(url, {
|
||||||
|
mode: "cors",
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setIsPublishing(false);
|
||||||
|
if (response.status !== 200) {
|
||||||
|
toast.error("Failed to publish partner");
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
toast.success("Partner details successfully updated");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setIsPublishing(false);
|
||||||
|
toast.error("Failed to update partner details: " + error?.message);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle Partner Publish Status
|
||||||
|
const handleTogglePublishStatus = () => {
|
||||||
|
setIsToggling(true);
|
||||||
|
const newPublishStatus = !partnerData?.public;
|
||||||
|
const url = globalUrl + "/api/v1/partners/" + userdata?.active_org?.id;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
id: partnerData.id?.trim() || null,
|
||||||
|
name: partnerData.name?.trim(),
|
||||||
|
org_id: selectedOrganization?.id?.trim(),
|
||||||
|
description: partnerData.description?.trim(),
|
||||||
|
website_url: partnerData.website_url?.trim(),
|
||||||
|
article_url: partnerData.article_url?.trim(),
|
||||||
|
partner_type: partnerTypes,
|
||||||
|
usecases: partnerData?.usecases || [],
|
||||||
|
expertise: partnerData?.expertise || [],
|
||||||
|
services: partnerData?.services || [],
|
||||||
|
solutions: partnerData?.solutions || [],
|
||||||
|
country: partnerData?.country || "",
|
||||||
|
region: partnerData?.region || "",
|
||||||
|
image_url: partnerData?.image_url?.trim(),
|
||||||
|
landscape_image_url: partnerData?.landscape_image_url?.trim(),
|
||||||
|
public: newPublishStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
|
mode: "cors",
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setIsToggling(false);
|
||||||
|
if (response.status !== 200) {
|
||||||
|
toast.error("Failed to update publish status");
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
// Update local state
|
||||||
|
setPartnerData(prev => ({
|
||||||
|
...prev,
|
||||||
|
public: newPublishStatus
|
||||||
|
}));
|
||||||
|
toast.success(`Partner ${newPublishStatus ? 'published' : 'unpublished'} successfully`);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setIsToggling(false);
|
||||||
|
toast.error("Failed to update publish status: " + error?.message);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ width: "100%", boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor, borderRadius: '16px', }}>
|
||||||
|
<div style={{ height: "100%", width: "100%", overflowX: 'hidden', scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}} >
|
||||||
|
<div style={{ marginBottom: 40 }}>
|
||||||
|
<div style={{display:"flex", alignItems:"center", justifyContent:"space-between"}}>
|
||||||
|
<div style={{width:'100%'}}>
|
||||||
|
<Box
|
||||||
|
sx={{display:"flex", alignItems:"flex-start", gap:2, justifyContent:"flex-start"
|
||||||
|
}}>
|
||||||
|
<Typography variant='h3' sx={{ marginBottom: "15px", marginTop: 0, }}>Configuration</Typography>
|
||||||
|
{Object?.entries(partnerTypes)?.map(([key, value]) => (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
borderRadius: "999px",
|
||||||
|
py: 1.2,
|
||||||
|
px: 2.5,
|
||||||
|
fontSize: "13px",
|
||||||
|
fontWeight: 500,
|
||||||
|
fontFamily: theme.typography.fontFamily,
|
||||||
|
color: "#fff",
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
border: `1.5px solid ${
|
||||||
|
partnerTypeColors[key]
|
||||||
|
}`,
|
||||||
|
transition: "all 0.2s ease",
|
||||||
|
textAlign: "center",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
color: partnerTypeColors[key],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{key.replace("_", " ").replace(/\b\w/g, char => char.toUpperCase())}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%",
|
||||||
|
marginTop: 0.5,
|
||||||
|
}}>
|
||||||
|
<Typography variant="body2" style={{ color: theme.palette.text.secondary, fontSize: 16, maxWidth: "60%" }}>
|
||||||
|
Set up and manage partner details and information to be displayed on the Partners page.
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{ display: "flex", gap: 2, alignItems: "center" }}>
|
||||||
|
{isPartner && (
|
||||||
|
<>
|
||||||
|
{/* View Partner Page Button */}
|
||||||
|
<Tooltip title="View Partner Page">
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
backgroundColor: theme.palette.action.hover,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.action.selected,
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onClick={handleOpenPartnerPage}
|
||||||
|
disabled={!partnerData?.id}
|
||||||
|
>
|
||||||
|
<OpenInNewIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
{/* Update Details Button */}
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
fontSize: 16,
|
||||||
|
textTransform: 'capitalize',
|
||||||
|
boxShadow: "none",
|
||||||
|
px: 4,
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
disabled={isPublishing || isToggling}
|
||||||
|
onClick={handleUpdatePartnerDetails}
|
||||||
|
>
|
||||||
|
{isPublishing ? "Updating..." : "Update Details"}
|
||||||
|
</Button>
|
||||||
|
{/* Toggle Publish/Unpublish Button */}
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
fontSize: 16,
|
||||||
|
textTransform: 'capitalize',
|
||||||
|
boxShadow: "none",
|
||||||
|
marginRight: 4,
|
||||||
|
px: 3,
|
||||||
|
backgroundColor: partnerData?.public ? "#FD4C62" : "#4caf50",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: partnerData?.public ? "#FD4C62" : "#4caf50"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
disabled={isToggling || isPublishing}
|
||||||
|
onClick={handleTogglePublishStatus}
|
||||||
|
>
|
||||||
|
{isToggling ? (partnerData?.public ? "Unpublishing..." : "Publishing...") : (partnerData?.public ? "Unpublish" : "Publish")}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isPartner && (
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
fontSize: 16,
|
||||||
|
textTransform: 'capitalize',
|
||||||
|
boxShadow: "none",
|
||||||
|
px: 5,
|
||||||
|
textDecoration: "none",
|
||||||
|
marginRight: 4
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
if(!isCloud){
|
||||||
|
navigate("/become-partner")
|
||||||
|
}else{
|
||||||
|
window.open("https://shuffler.io/become-partner")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Become a partner
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<PartnerHeader
|
||||||
|
isCloud={isCloud}
|
||||||
|
userdata={userdata}
|
||||||
|
isPublishing={isPublishing}
|
||||||
|
setSelectedOrganization={setSelectedOrganization}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
selectedOrganization={selectedOrganization}
|
||||||
|
isEditOrgTab={true}
|
||||||
|
loadingPartnerData={loadingPartnerData}
|
||||||
|
partnerData={partnerData}
|
||||||
|
setPartnerData={setPartnerData}
|
||||||
|
handleGetOrg={handleGetOrg}
|
||||||
|
/>
|
||||||
|
<PartnerDetails
|
||||||
|
isCloud={isCloud}
|
||||||
|
userdata={userdata}
|
||||||
|
partnerData={partnerData}
|
||||||
|
isPublishing={isPublishing}
|
||||||
|
loadingPartnerData={loadingPartnerData}
|
||||||
|
setPartnerData={setPartnerData}
|
||||||
|
setSelectedOrganization={setSelectedOrganization}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
selectedOrganization={selectedOrganization}
|
||||||
|
isEditOrgTab={true}
|
||||||
|
handleGetOrg={handleGetOrg}
|
||||||
|
serverside={serverside}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PartnerSettings;
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
import React, { useEffect, useState, useCallback, useContext } from 'react';
|
||||||
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
|
import Branding from "../components/Branding.jsx";
|
||||||
|
import { ToastContainer, toast } from "react-toastify";
|
||||||
|
import { Button } from '@mui/material';
|
||||||
|
import { getTheme } from '../theme.jsx';
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
import PartnerSettings from '../components/PartnerSettings.jsx';
|
||||||
|
import PartnersUsecasesTab from '../components/PartnersUsecasesTab.jsx';
|
||||||
|
import PartnersApps from '../components/PartnerApps.jsx';
|
||||||
|
import PartnerArticles from '../components/PartnersArticles.jsx';
|
||||||
|
const PartnerTab = (props) => {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const {
|
||||||
|
userdata,
|
||||||
|
globalUrl,
|
||||||
|
serverside,
|
||||||
|
isCloud,
|
||||||
|
setSelectedOrganization,
|
||||||
|
selectedOrganization, handleGetOrg,
|
||||||
|
handleStatusChange,
|
||||||
|
isLoaded,
|
||||||
|
removeCookie
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
|
||||||
|
const [selectedTab, setSelectedTab] = useState('partner_settings');
|
||||||
|
const [loadingPartnerData, setLoadingPartnerData] = useState(false);
|
||||||
|
const [curIndex, setCurIndex] = React.useState(0);
|
||||||
|
const [partnerData, setPartnerData] = React.useState({
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
image_url: "",
|
||||||
|
landscape_image_url: "",
|
||||||
|
website_url: "",
|
||||||
|
article_url: "",
|
||||||
|
expertise: [],
|
||||||
|
usecases: [],
|
||||||
|
services: [],
|
||||||
|
solutions: [],
|
||||||
|
country: "",
|
||||||
|
region: "",
|
||||||
|
partner_type: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tabsOnPartnerTab = [ 'Partner Settings', 'Usecases', 'Apps', 'AI Agents', 'Articles', 'Branding'];
|
||||||
|
|
||||||
|
const { themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(!isCloud || !userdata?.active_org?.is_partner) {
|
||||||
|
// If the user is not a partner or if it's not a cloud environment do not make api call :)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoadingPartnerData(true);
|
||||||
|
const url = globalUrl + "/api/v1/partners/" + userdata?.active_org?.id;
|
||||||
|
fetch(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
toast("Failed to get partner data")
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
if(responseJson.success) {
|
||||||
|
setPartnerData(responseJson?.partner);
|
||||||
|
console.log("responseJson", responseJson)
|
||||||
|
setLoadingPartnerData(false);
|
||||||
|
}else{
|
||||||
|
setLoadingPartnerData(false);
|
||||||
|
toast(responseJson?.reason)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setLoadingPartnerData(false);
|
||||||
|
})
|
||||||
|
}, [globalUrl]);
|
||||||
|
|
||||||
|
// Used to auto select the tab based on the url : partner_tab
|
||||||
|
useEffect(() => {
|
||||||
|
const queryParams = new URLSearchParams(location.search);
|
||||||
|
const tabName = queryParams.get('partner_tab');
|
||||||
|
if (tabName) {
|
||||||
|
const decodedTabName = decodeURIComponent(tabName);
|
||||||
|
setSelectedTab(decodedTabName);
|
||||||
|
if (decodedTabName === 'partner_settings') {
|
||||||
|
setCurIndex(0);
|
||||||
|
} else if(decodedTabName === 'usecases'){
|
||||||
|
setCurIndex(1)
|
||||||
|
}else if (decodedTabName === 'apps'){
|
||||||
|
setCurIndex(2);
|
||||||
|
} else if (decodedTabName === 'aiagents') {
|
||||||
|
setCurIndex(3);
|
||||||
|
} else if (decodedTabName === 'articles') {
|
||||||
|
setCurIndex(4);
|
||||||
|
} else if (decodedTabName === 'branding') {
|
||||||
|
setCurIndex(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [location.search]);
|
||||||
|
|
||||||
|
// Tab click on partner tab
|
||||||
|
const handleTabClick = (tabName) => {
|
||||||
|
const formattedTabName = tabName.toLowerCase().replace(/[\s&]+/g, '');
|
||||||
|
const encodedTabName = encodeURIComponent(formattedTabName);
|
||||||
|
setSelectedTab(formattedTabName);
|
||||||
|
document.title = `Shuffle - partner - ${formattedTabName}`;
|
||||||
|
navigate(`?partner_tab=${encodedTabName}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rendering the content based on the selected tab
|
||||||
|
const renderContent = () => {
|
||||||
|
switch (selectedTab) {
|
||||||
|
case 'partner_settings':
|
||||||
|
return <PartnerSettings isCloud={isCloud} loadingPartnerData={loadingPartnerData} partnerData={partnerData} setPartnerData={setPartnerData} handleStatusChange={handleStatusChange} userdata={userdata} globalUrl={globalUrl} serverside={serverside} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} selectedTab={selectedTab} />;
|
||||||
|
case 'usecases':
|
||||||
|
return <PartnersUsecasesTab isCloud={isCloud} partnerData={partnerData} setPartnerData={setPartnerData} handleStatusChange={handleStatusChange} userdata={userdata} globalUrl={globalUrl} serverside={serverside} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} selectedTab={selectedTab} />;
|
||||||
|
case `apps`:
|
||||||
|
return <PartnersApps isCloud={isCloud} partnerData={partnerData} setPartnerData={setPartnerData} handleStatusChange={handleStatusChange} userdata={userdata} globalUrl={globalUrl} serverside={serverside} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} selectedTab={selectedTab} />;
|
||||||
|
case 'articles' :
|
||||||
|
return <PartnerArticles isCloud={isCloud} partnerData={partnerData} setPartnerData={setPartnerData} handleStatusChange={handleStatusChange} userdata={userdata} globalUrl={globalUrl} serverside={serverside} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} selectedTab={selectedTab} />;
|
||||||
|
case `ai_agents`:
|
||||||
|
return <PartnerArticles isCloud={isCloud} partnerData={partnerData} setPartnerData={setPartnerData} handleStatusChange={handleStatusChange} userdata={userdata} globalUrl={globalUrl} serverside={serverside} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} selectedTab={selectedTab} />;
|
||||||
|
case 'branding':
|
||||||
|
return <Branding
|
||||||
|
isCloud={isCloud}
|
||||||
|
userdata={userdata}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
handleGetOrg={handleGetOrg}
|
||||||
|
selectedOrganization={selectedOrganization}
|
||||||
|
clickedFromOrgTab={true}
|
||||||
|
setSelectedOrganization={setSelectedOrganization}
|
||||||
|
/>;
|
||||||
|
default:
|
||||||
|
return <PartnerSettings isCloud={isCloud} partnerData={partnerData} setPartnerData={setPartnerData} handleStatusChange={handleStatusChange} userdata={userdata} globalUrl={globalUrl} serverside={serverside} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isTabDisabled = (tabName) => {
|
||||||
|
// If user is a support user, enable all tabs
|
||||||
|
if (userdata?.support) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-support users, apply the following restrictions:
|
||||||
|
|
||||||
|
// For onPrem only partner settings and branding are enabled
|
||||||
|
if (
|
||||||
|
!isCloud &&
|
||||||
|
(tabName === "Usecases" ||
|
||||||
|
tabName === "Apps" ||
|
||||||
|
tabName === "AI Agents" ||
|
||||||
|
tabName === "Articles")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable Apps, Articles, and AI Agents for all non-support users
|
||||||
|
if (
|
||||||
|
tabName === "Apps" ||
|
||||||
|
tabName === "Articles" ||
|
||||||
|
tabName === "AI Agents"
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable Usecases tab for cloud users if not a partner or is in a sub-org
|
||||||
|
if (isCloud && tabName === "Usecases") {
|
||||||
|
if (
|
||||||
|
!userdata?.active_org?.is_partner ||
|
||||||
|
userdata?.active_org?.is_sub_org
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable Branding tab if not an integration partner
|
||||||
|
const isIntegrationPartner =
|
||||||
|
userdata &&
|
||||||
|
userdata?.org_status?.includes("integration_partner") &&
|
||||||
|
!userdata?.org_status?.includes("sub_org");
|
||||||
|
if (tabName === "Branding" && !isIntegrationPartner) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the tab by default
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ height: "100%", width: "100%", color: theme.palette.platformColor, backgroundColor: theme.palette.platformColor, borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: theme.palette.defaultBorder, boxSizing: 'border-box' }}>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-around', width: "100%", borderBottom: theme.palette.defaultBorder ,boxSizing: 'border-box' }}>
|
||||||
|
{tabsOnPartnerTab?.map((tabName, index) => (
|
||||||
|
<div style={{ pointerEvents: 'auto', width: '100%',}}>
|
||||||
|
<Button
|
||||||
|
key={tabName}
|
||||||
|
onClick={() => {
|
||||||
|
setCurIndex(index);
|
||||||
|
handleTabClick(index === 0 ? "partner_settings" : tabName.toLowerCase().replace(/[\s&]+/g, ''));
|
||||||
|
}}
|
||||||
|
disabled={isTabDisabled(tabName)}
|
||||||
|
variant="text"
|
||||||
|
sx={{
|
||||||
|
"&.MuiButton-root": {
|
||||||
|
padding: '28px 0',
|
||||||
|
borderBottom: index === curIndex ? '2px solid #FF8444' : 'none',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontWeight: index === curIndex ? 'bold' : 'normal',
|
||||||
|
color: index === curIndex ? "#FF8444" : theme.palette.text.primary,
|
||||||
|
textTransform: 'none',
|
||||||
|
fontSize: 16,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
borderRadius: 0,
|
||||||
|
},
|
||||||
|
"&: hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor
|
||||||
|
},
|
||||||
|
"&.Mui-disabled": {
|
||||||
|
color: "#6F6F6F",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tabName}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'center', width: "100%", height: "100%", paddingBottom: 200, boxSizing:'border-box'}}>
|
||||||
|
{renderContent()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PartnerTab;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Box, Typography } from '@mui/material'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const PartnersArticles = () => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
minHeight: "500px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>Partner Articles</Typography>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PartnersArticles
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { getTheme } from "../theme.jsx";
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import theme from "../theme.jsx";
|
|
||||||
import { useNavigate, Link } from "react-router-dom";
|
import { useNavigate, Link } from "react-router-dom";
|
||||||
import { findSpecificApp } from "../components/AppFramework.jsx"
|
import { findSpecificApp } from "../components/AppFramework.jsx"
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import {
|
import {
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -23,7 +23,8 @@ import {
|
|||||||
|
|
||||||
const Priority = (props) => {
|
const Priority = (props) => {
|
||||||
const { globalUrl, clickedFromOrgTab,userdata, serverside, priority, checkLogin, setAdminTab, setCurTab, appFramework, } = props;
|
const { globalUrl, clickedFromOrgTab,userdata, serverside, priority, checkLogin, setAdminTab, setCurTab, appFramework, } = props;
|
||||||
|
const { themeMode, supportEmail } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
@@ -113,7 +114,7 @@ const Priority = (props) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast("Failed dismissing alert. Please contact support@shuffler.io if this persists.");
|
toast(`Failed dismissing alert. Please contact ${supportEmail} if this persists.`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,10 +122,10 @@ const Priority = (props) => {
|
|||||||
const srcSize = realignedSrc ? 35 : 30
|
const srcSize = realignedSrc ? 35 : 30
|
||||||
const dstSize = realignedDst ? 35 : 30
|
const dstSize = realignedDst ? 35 : 30
|
||||||
return (
|
return (
|
||||||
<div style={{border: priority.active === false ? "1px solid #000000" : priority.severity === 1 ? "1px solid #f85a3e" : clickedFromOrgTab ?null:"1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, marginTop: 10, marginBottom: 10, padding: clickedFromOrgTab ? 24:15, textAlign: "center", minHeight: isCloud ? 70 : 100, maxHeight: isCloud ? 70 : 100, textAlign: "left", backgroundColor: clickedFromOrgTab ? "#1A1A1A": theme.palette.surfaceColor, display: "flex", }}>
|
<div style={{border: priority.active === false ? "1px solid #000000" : priority.severity === 1 ? "1px solid #f85a3e" : clickedFromOrgTab ?null:"1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, marginTop: 10, marginBottom: 10, padding: clickedFromOrgTab ? 24:15, textAlign: "center", minHeight: isCloud ? 70 : 100, maxHeight: isCloud ? 70 : 100, textAlign: "left", backgroundColor: clickedFromOrgTab ? theme.palette.backgroundColor : theme.palette.surfaceColor, display: "flex", }}>
|
||||||
<div style={{flex: 2, overflow: "hidden",}}>
|
<div style={{flex: 2, overflow: "hidden",}}>
|
||||||
<span style={{display: "flex", }}>
|
<span style={{display: "flex", }}>
|
||||||
{priority.type === "usecase" || priority.type == "apps" ? <AutoFixHighIcon style={{height: 19, width: 19, marginLeft: 3, marginRight: 10, }}/> : null}
|
{priority.type === "usecase" || priority.type == "apps" ? <AutoFixHighIcon style={{height: 19, width: 19, marginLeft: 3, marginRight: 10, color: theme.palette.text.primary}}/> : null}
|
||||||
<Typography variant="body1" >
|
<Typography variant="body1" >
|
||||||
{priority.name}
|
{priority.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -138,7 +139,7 @@ const Priority = (props) => {
|
|||||||
|
|
||||||
{newdescription.split("&").length > 3 ?
|
{newdescription.split("&").length > 3 ?
|
||||||
<span style={{display: "flex", }}>
|
<span style={{display: "flex", }}>
|
||||||
<ArrowForwardIcon style={{marginLeft: 15, marginRight: 15, }}/>
|
<ArrowForwardIcon style={{marginLeft: 15, marginRight: 15, color: theme.palette.text.primary }}/>
|
||||||
<img src={newdescription.split("&")[3]} alt={priority.name+"2"} style={{height: dstSize, width: dstSize, marginRight: realignedDst ? -5 : 10, borderRadius: theme.palette?.borderRadius-3, marginTop: realignedDst ? 5 : 0 }} />
|
<img src={newdescription.split("&")[3]} alt={priority.name+"2"} style={{height: dstSize, width: dstSize, marginRight: realignedDst ? -5 : 10, borderRadius: theme.palette?.borderRadius-3, marginTop: realignedDst ? 5 : 0 }} />
|
||||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 3}}>
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 3}}>
|
||||||
{newdescription.split("&")[2]}
|
{newdescription.split("&")[2]}
|
||||||
@@ -154,7 +155,7 @@ const Priority = (props) => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{flex: 1, display: "flex", marginLeft: 30, }}>
|
<div style={{flex: 1, display: "flex", marginLeft: 30, }}>
|
||||||
<Button style={{height: 50, borderRadius: 4, fontSize:16, boxShadow: clickedFromOrgTab ? "none":null,textTransform: clickedFromOrgTab ? 'capitalize':null, marginTop: 8, width: 175, marginRight: 10, color: priority.active === false ? "white" :clickedFromOrgTab ?"#ff8544": "black", backgroundColor: priority.active === false ? theme.palette.inputColor :clickedFromOrgTab?"transparent":"rgba(255,255,255,0.8)", border: "1px solid #ff8544"}} variant="contained" color="secondary" onClick={() => {
|
<Button style={{height: 50, borderRadius: 4, fontSize:16, boxShadow: clickedFromOrgTab ? "none":null,textTransform: clickedFromOrgTab ? 'capitalize':null, marginTop: 8, width: 175, marginRight: 10, }} variant="outlined" color="primary" onClick={() => {
|
||||||
|
|
||||||
if (isCloud) {
|
if (isCloud) {
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
@@ -180,10 +181,9 @@ const Priority = (props) => {
|
|||||||
Explore
|
Explore
|
||||||
</Button>
|
</Button>
|
||||||
{priority.active === true ?
|
{priority.active === true ?
|
||||||
<Button style={{borderRadius: 25, fontSize:16, boxShadow: clickedFromOrgTab ? "none":null,textTransform: clickedFromOrgTab ? 'capitalize':null, width: 100, height: 50, marginTop: 8, }} variant="text" color="secondary" onClick={() => {
|
<Button style={{borderRadius: 4, fontSize:16, boxShadow: clickedFromOrgTab ? "none":null,textTransform: clickedFromOrgTab ? 'capitalize':null, width: 100, height: 50, marginTop: 8, }} variant="outlined" color="secondary" onClick={() => {
|
||||||
// dismiss -> get envs
|
// dismiss -> get envs
|
||||||
changeRecommendation(priority, "dismiss")
|
changeRecommendation(priority, "dismiss")
|
||||||
|
|
||||||
// Check window location if it's /workflows
|
// Check window location if it's /workflows
|
||||||
if (window.location.pathname === "/workflows") {
|
if (window.location.pathname === "/workflows") {
|
||||||
// Set local storage to hide priorities for now
|
// Set local storage to hide priorities for now
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react"
|
import React, {useContext} from "react"
|
||||||
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
@@ -10,14 +10,20 @@ import {
|
|||||||
} from "@mui/material"
|
} from "@mui/material"
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import theme from "../theme.jsx";
|
import theme from "../theme.jsx";
|
||||||
|
import { getTheme } from "../theme.jsx";
|
||||||
import {
|
import {
|
||||||
Lock as LockIcon,
|
Lock as LockIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
|
||||||
// onclickHandler = function override from parent onclick
|
// onclickHandler = function override from parent onclick
|
||||||
const RecentWorkflow = ({ workflow, onclickHandler, leftNavOpen, currentWorkflowId, }) => {
|
const RecentWorkflow = ({ workflow, onclickHandler, leftNavOpen, currentWorkflowId, }) => {
|
||||||
|
|
||||||
|
const { themeMode } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [hovered, setHovered] = React.useState(false)
|
const [hovered, setHovered] = React.useState(false)
|
||||||
@@ -87,7 +93,7 @@ const RecentWorkflow = ({ workflow, onclickHandler, leftNavOpen, currentWorkflow
|
|||||||
transition: "opacity 0.1s",
|
transition: "opacity 0.1s",
|
||||||
|
|
||||||
borderRadius: theme.palette?.borderRadius,
|
borderRadius: theme.palette?.borderRadius,
|
||||||
backgroundColor: hovered || currentWorkflowId === workflow.id ? "#1f1f1f" : "transparent",
|
backgroundColor: hovered || currentWorkflowId === workflow.id ? theme.palette.hoverColor : "transparent",
|
||||||
}}
|
}}
|
||||||
disableRipple
|
disableRipple
|
||||||
>
|
>
|
||||||
@@ -127,7 +133,6 @@ const RecentWorkflow = ({ workflow, onclickHandler, leftNavOpen, currentWorkflow
|
|||||||
))}
|
))}
|
||||||
<Typography
|
<Typography
|
||||||
style={{
|
style={{
|
||||||
color: "#CDCDCD",
|
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
maxWidth: 180,
|
maxWidth: 180,
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import React, { useState, useEffect, useLayoutEffect } from "react";
|
import React, { useState, useEffect, useLayoutEffect, useContext, useMemo } from "react";
|
||||||
import * as cytoscape from "cytoscape";
|
import * as cytoscape from "cytoscape";
|
||||||
import CytoscapeComponent from "react-cytoscapejs";
|
import CytoscapeComponent from "react-cytoscapejs";
|
||||||
import cystyle from "../defaultCytoscapeStyle.jsx";
|
import defaultCytoscapeStyle from "../defaultCytoscapeStyle.jsx";
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
|
import { getTheme } from "../theme.jsx";
|
||||||
|
|
||||||
const surfaceColor = "#27292D";
|
const surfaceColor = "#27292D";
|
||||||
const CytoscapeWrapper = (props) => {
|
const CytoscapeWrapper = (props) => {
|
||||||
const { globalUrl, inworkflow, height, width } = props;
|
const { globalUrl, inworkflow, height, width } = props;
|
||||||
|
const {themeMode} = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
const cystyle = useMemo(() => defaultCytoscapeStyle(theme), [themeMode]);
|
||||||
const [elements, setElements] = useState([]);
|
const [elements, setElements] = useState([]);
|
||||||
const [workflow, setWorkflow] = useState(inworkflow);
|
const [workflow, setWorkflow] = useState(inworkflow);
|
||||||
const [cy, setCy] = React.useState();
|
const [cy, setCy] = React.useState();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TextField,
|
TextField,
|
||||||
@@ -17,10 +17,11 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Switch,
|
Switch,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
|
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
||||||
import Pagination from '@mui/material/Pagination';
|
import Pagination from '@mui/material/Pagination';
|
||||||
@@ -39,7 +40,8 @@ import {
|
|||||||
EditNote as EditNoteIcon,
|
EditNote as EditNoteIcon,
|
||||||
AccountTree as AccountTreeIcon,
|
AccountTree as AccountTreeIcon,
|
||||||
Cached as CachedIcon,
|
Cached as CachedIcon,
|
||||||
FilterAltOff as FilterAltOffIcon
|
FilterAltOff as FilterAltOffIcon,
|
||||||
|
Send as SendIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'
|
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'
|
||||||
@@ -69,6 +71,8 @@ const RuntimeDebugger = (props) => {
|
|||||||
const [endTime, setEndTime] = useState("")
|
const [endTime, setEndTime] = useState("")
|
||||||
const [startTime, setStartTime] = useState("")
|
const [startTime, setStartTime] = useState("")
|
||||||
const [totalCount, setTotalCount] = useState(0)
|
const [totalCount, setTotalCount] = useState(0)
|
||||||
|
const {themeMode, supportEmail} = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const [workflow, setWorkflow] = useState({})
|
const [workflow, setWorkflow] = useState({})
|
||||||
const [ignoreOrg, setIgnoreOrg] = useState(false)
|
const [ignoreOrg, setIgnoreOrg] = useState(false)
|
||||||
@@ -107,7 +111,7 @@ const RuntimeDebugger = (props) => {
|
|||||||
|
|
||||||
var maxworkflows = 5
|
var maxworkflows = 5
|
||||||
|
|
||||||
console.log("Looking for MAX this amount of workflows: ", maxworkflows)
|
//console.log("Looking for MAX this amount of workflows: ", maxworkflows)
|
||||||
for (let key in workflows) {
|
for (let key in workflows) {
|
||||||
if (key > maxworkflows) {
|
if (key > maxworkflows) {
|
||||||
break
|
break
|
||||||
@@ -347,6 +351,9 @@ const RuntimeDebugger = (props) => {
|
|||||||
source = "rerun of a previous run"
|
source = "rerun of a previous run"
|
||||||
} else if (source === "form") {
|
} else if (source === "form") {
|
||||||
foundSource = <EditNoteIcon style={{color: theme.palette.primary.secondary, height: imageSize, width: imageSize, }} />
|
foundSource = <EditNoteIcon style={{color: theme.palette.primary.secondary, height: imageSize, width: imageSize, }} />
|
||||||
|
} else if (source === "single_action" || source == "single_api" || source === "direct_api") {
|
||||||
|
foundSource = <SendIcon color="secondary" style={{height: imageSize-5, }} />
|
||||||
|
source = "Single API call"
|
||||||
} else {
|
} else {
|
||||||
source = "manual"
|
source = "manual"
|
||||||
}
|
}
|
||||||
@@ -354,12 +361,12 @@ const RuntimeDebugger = (props) => {
|
|||||||
var imageSource = "";
|
var imageSource = "";
|
||||||
if (params?.row?.org?.id?.length > 0) {
|
if (params?.row?.org?.id?.length > 0) {
|
||||||
if (params?.row?.org?.image?.length > 0){
|
if (params?.row?.org?.image?.length > 0){
|
||||||
imageSource = params?.row.org?.image
|
imageSource = params?.row?.org?.image
|
||||||
}else {
|
}else {
|
||||||
imageSource = "/images/no_image.png"
|
imageSource = "/images/no_image.png"
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
if (userdata.active_org.image?.length > 0){
|
if (userdata?.active_org?.image?.length > 0){
|
||||||
imageSource = userdata?.active_org?.image
|
imageSource = userdata?.active_org?.image
|
||||||
}else {
|
}else {
|
||||||
imageSource = "/images/no_image.png"
|
imageSource = "/images/no_image.png"
|
||||||
@@ -629,7 +636,7 @@ const RuntimeDebugger = (props) => {
|
|||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip arrow title="Force continue workflow. Only workflows for workflows in EXECUTING state. This is NOT a rerun, but way for Shuffle to figure out the next steps automatically. If the execution doesn't finish even after trying this, please contact support@shuffler.io">
|
<Tooltip arrow title={`Force continue workflow. Only workflows for workflows in EXECUTING state. This is NOT a rerun, but way for Shuffle to figure out the next steps automatically. If the execution doesn't finish even after trying this, please contact ${supportEmail}`}>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={{marginLeft: 5, }}
|
style={{marginLeft: 5, }}
|
||||||
disabled={params.row.status !== "EXECUTING"}
|
disabled={params.row.status !== "EXECUTING"}
|
||||||
@@ -812,7 +819,7 @@ const RuntimeDebugger = (props) => {
|
|||||||
<div style={{display: "flex", paddingTop: 50, }}>
|
<div style={{display: "flex", paddingTop: 50, }}>
|
||||||
<div style={{display: 'flex', flexDirection: 'column'}}>
|
<div style={{display: 'flex', flexDirection: 'column'}}>
|
||||||
<div style={{display: "flex", width: "100%", }}>
|
<div style={{display: "flex", width: "100%", }}>
|
||||||
<h1 style={{flex: 3, whiteSpace: "nowrap" }}>Workflow Run Debugger {totalCount !== 0 ? ` (~${totalCount})` : ""}</h1>
|
<Typography variant="h3" style={{flex: 3, whiteSpace: "nowrap" }}>Workflow Run Debugger {totalCount !== 0 ? ` (~${totalCount})` : ""}</Typography>
|
||||||
{selectedWorkflowExecutions.length > 0 ?
|
{selectedWorkflowExecutions.length > 0 ?
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Tooltip title="Reruns ALL selected workflows. This will make a new execution for them, and not continue the existing.">
|
<Tooltip title="Reruns ALL selected workflows. This will make a new execution for them, and not continue the existing.">
|
||||||
@@ -890,7 +897,8 @@ const RuntimeDebugger = (props) => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
|
color: theme.palette.textColor,
|
||||||
marginTop: 20,
|
marginTop: 20,
|
||||||
marginLeft: 10,
|
marginLeft: 10,
|
||||||
marginRight: 12,
|
marginRight: 12,
|
||||||
@@ -901,7 +909,8 @@ const RuntimeDebugger = (props) => {
|
|||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
|
color: theme.palette.textColor,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
height: 51,
|
height: 51,
|
||||||
width: 693,
|
width: 693,
|
||||||
@@ -951,7 +960,7 @@ const RuntimeDebugger = (props) => {
|
|||||||
}
|
}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
/>
|
/>
|
||||||
<Typography variant="body2" style={{color: "white", }}>Show workflow runs from suborgs</Typography>
|
<Typography variant="body2">Show workflow runs from suborgs</Typography>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -999,8 +1008,8 @@ const RuntimeDebugger = (props) => {
|
|||||||
classes={{ inputRoot: classes.inputRoot }}
|
classes={{ inputRoot: classes.inputRoot }}
|
||||||
ListboxProps={{
|
ListboxProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(option) => {
|
getOptionLabel={(option) => {
|
||||||
@@ -1018,7 +1027,7 @@ const RuntimeDebugger = (props) => {
|
|||||||
options={workflows}
|
options={workflows}
|
||||||
fullWidth
|
fullWidth
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
height: 50,
|
height: 50,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginLeft: 5,
|
marginLeft: 5,
|
||||||
@@ -1063,8 +1072,13 @@ const RuntimeDebugger = (props) => {
|
|||||||
}>
|
}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
color: data.id === workflow.id ? "red" : "white",
|
color: data.id === workflow.id ? "red" : theme.palette.textColor,
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
value={data}
|
value={data}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@@ -1082,9 +1096,16 @@ const RuntimeDebugger = (props) => {
|
|||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
|
color: theme.palette.textColor,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
}}
|
}}
|
||||||
|
inputProps={{
|
||||||
|
style: {
|
||||||
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
|
color: theme.palette.textColor,
|
||||||
|
},
|
||||||
|
}}
|
||||||
{...params}
|
{...params}
|
||||||
label="Workflow"
|
label="Workflow"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -1128,9 +1149,7 @@ const RuntimeDebugger = (props) => {
|
|||||||
|
|
||||||
<Tooltip title="Clear all filters and search parameters">
|
<Tooltip title="Clear all filters and search parameters">
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: 10, minHeight: 60, marginTop: 10, backgroundColor: "#1a1a1a", border: "1px solid #424242", boxShadow: 'none', borderRadius: 4, width: 81, height: 51, marginRight: 15 }}
|
style={{ marginLeft: 10, minHeight: 60, marginTop: 10, backgroundColor: theme.palette.backgroundColor, border: "1px solid #424242", boxShadow: 'none', borderRadius: 4, width: 81, height: 51, marginRight: 15 }}
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setWorkflowId("")
|
setWorkflowId("")
|
||||||
setWorkflow({"id": "", "name": "All Workflows"})
|
setWorkflow({"id": "", "name": "All Workflows"})
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { forwardRef, memo, useContext, useEffect } from 'react';
|
import React, { forwardRef, memo, useContext, useEffect } from 'react';
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
import { toast } from "react-toastify" ;
|
import { toast } from "react-toastify" ;
|
||||||
import {
|
import {
|
||||||
Divider,
|
Divider,
|
||||||
@@ -33,6 +33,9 @@ const SchedulesTab = memo((props) => {
|
|||||||
const [pipelineModalOpen, setPipelineModalOpen] = React.useState(false);
|
const [pipelineModalOpen, setPipelineModalOpen] = React.useState(false);
|
||||||
const [newPipelineValue, setNewPipelineValue] = React.useState("export | sigma /tmp/sigma_rules | to SHUFFLE_WEBHOOK");
|
const [newPipelineValue, setNewPipelineValue] = React.useState("export | sigma /tmp/sigma_rules | to SHUFFLE_WEBHOOK");
|
||||||
|
|
||||||
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (allSchedules.length === 0 && webHooks.length === 0 && pipelines.length === 0) {
|
if (allSchedules.length === 0 && webHooks.length === 0 && pipelines.length === 0) {
|
||||||
handleGetAllTriggers()
|
handleGetAllTriggers()
|
||||||
@@ -142,11 +145,11 @@ const SchedulesTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<span style={{ color: "white" }}>
|
<Typography variant='h5' color="textPrimary" >
|
||||||
Run a Tenzir pipeline
|
Run a Tenzir pipeline
|
||||||
</span>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 10, }}>
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 10, }}>
|
||||||
Alpha feature. Deploys to the first available Orborus location. <a href="https://docs.tenzir.com/pipelines" target="_blank" rel="noopener noreferrer" style={{ color: "#ff8544" }}>Explore Tenzir Pipelines</a>. The example below exports everything in the Tenzir database, runs Sigma rules on it, and forwards the results to a Shuffle webhook.
|
Alpha feature. Deploys to the first available Orborus location. <a href="https://docs.tenzir.com/pipelines" target="_blank" rel="noopener noreferrer" style={{ color: theme.palette.primary.main }}>Explore Tenzir Pipelines</a>. The example below exports everything in the Tenzir database, runs Sigma rules on it, and forwards the results to a Shuffle webhook.
|
||||||
</Typography>
|
</Typography>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -173,17 +176,16 @@ const SchedulesTab = memo((props) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", color: "#ff8544" }}
|
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", color: theme.palette.primary.main }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPipelineModalOpen(false)
|
setPipelineModalOpen(false)
|
||||||
}}
|
}}
|
||||||
color="primary"
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", backgroundColor: "#ff8544", color: "#1a1a1a" }}
|
style={{ borderRadius: "2px", fontSize: 16, textTransform: "none", }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
submitPipelineWrapper(newPipelineValue)
|
submitPipelineWrapper(newPipelineValue)
|
||||||
}}
|
}}
|
||||||
@@ -472,7 +474,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
transition: 'width 0.3s ease',
|
transition: 'width 0.3s ease',
|
||||||
padding: '27px 10px 27px 27px',
|
padding: '27px 10px 27px 27px',
|
||||||
backgroundColor: '#212121',
|
backgroundColor: theme.palette.platformColor,
|
||||||
borderTopRightRadius: 8,
|
borderTopRightRadius: 8,
|
||||||
borderBottomRightRadius: 8,
|
borderBottomRightRadius: 8,
|
||||||
borderLeft: '1px solid #494949',
|
borderLeft: '1px solid #494949',
|
||||||
@@ -480,36 +482,36 @@ const SchedulesTab = memo((props) => {
|
|||||||
|
|
||||||
{NewPipelineView}
|
{NewPipelineView}
|
||||||
|
|
||||||
<div style={{height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
|
<div style={{height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
|
||||||
<h2 style={{ marginBottom: 8, marginTop: 0, color: "#FFFFFF" }}>
|
<Typography variant='h5' color="textPrimary" style={{ marginBottom: 8, marginTop: 0, }}>
|
||||||
Triggers
|
Triggers
|
||||||
</h2>
|
</Typography>
|
||||||
<Typography variant="body1" style={{ marginBottom: 50, marginTop: 0, }} color="textSecondary">
|
<Typography variant="body2" style={{ marginBottom: 50, marginTop: 0, }} color="textSecondary">
|
||||||
Triggers are Automatic Workflow starters. <b>Status: Schedules ({allSchedules.length}), Webhooks ({webHooks.length}), Pipelines ({pipelines.length})</b>
|
Triggers are Automatic Workflow starters. <b>Status: Schedules ({allSchedules.length}), Webhooks ({webHooks.length}), Pipelines ({pipelines.length})</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 style={{ marginBottom: 8, marginTop: 0, color: "#FFFFFF" }}>
|
<Typography variant='h6' color="textPrimary" style={{ marginBottom: 8, marginTop: 0, fontWeight: 500}}>
|
||||||
Schedules
|
Schedules
|
||||||
</h4>
|
</Typography>
|
||||||
<span style={{color:textColor}}>
|
<Typography variant='body2' color="textSecondary">
|
||||||
Schedules used in Workflows. Makes locating and control easier.{" "}
|
Schedules used in Workflows. Makes locating and control easier.{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/organizations#schedules"
|
href="/docs/organizations#schedules"
|
||||||
style={{ color:"#FF8444" }}
|
style={{ color: theme.palette.primary.main }}
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div style={{height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
|
<div style={{height: "100%", width: "calc(100% - 20px)", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -525,7 +527,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0
|
paddingBottom: 0
|
||||||
}}>
|
}}>
|
||||||
<ListItem style={{width: "100%", paddingTop: 10, paddingBottom: 10, paddingRight: 10, borderBottom: "1px solid #494949", display: 'table-row'}}>
|
<ListItem style={{width: "100%", paddingTop: 10, paddingBottom: 10, paddingRight: 10, borderBottom: theme.palette.defaultBorder, display: 'table-row'}}>
|
||||||
{["Name", "Interval", "Environment", "Workflow", "Argument", "Action"].map((header, index) => (
|
{["Name", "Interval", "Environment", "Workflow", "Argument", "Action"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
key={index}
|
key={index}
|
||||||
@@ -535,7 +537,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -546,7 +548,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
key={rowIndex}
|
key={rowIndex}
|
||||||
style={{
|
style={{
|
||||||
display: "table-row",
|
display: "table-row",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(6)
|
{Array(6)
|
||||||
@@ -563,7 +565,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
height: "20px",
|
height: "20px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
@@ -575,13 +577,13 @@ const SchedulesTab = memo((props) => {
|
|||||||
):(
|
):(
|
||||||
allSchedules?.length === 0 ? (
|
allSchedules?.length === 0 ? (
|
||||||
<div style={{ textAlign: 'center'}}>
|
<div style={{ textAlign: 'center'}}>
|
||||||
<Typography style={{color: "#FFFFFF", fontSize: 16, padding: 20, textAlign: 'center'}}>No schedules found</Typography>
|
<Typography style={{color: theme.palette.text.primary, fontSize: 16, padding: 20, textAlign: 'center'}}>No schedules found</Typography>
|
||||||
</div>
|
</div>
|
||||||
):(
|
):(
|
||||||
allSchedules.map((schedule, index) => {
|
allSchedules.map((schedule, index) => {
|
||||||
var bgColor = "#212121"
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = "#1a1a1a";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -645,7 +647,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
style={{
|
style={{
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
color: "#f85a3e",
|
color: theme.palette.primary.main,
|
||||||
}}
|
}}
|
||||||
href={`/workflows/${schedule.workflow_id}`}
|
href={`/workflows/${schedule.workflow_id}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -658,7 +660,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
schedule.workflow_id !== "global"
|
schedule.workflow_id !== "global"
|
||||||
? "#FF8444"
|
? theme.palette.primary.main
|
||||||
: "grey",
|
: "grey",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -698,8 +700,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: schedule.status === "running" ? '#1a1a1a' : null,
|
width: 150,
|
||||||
backgroundColor: schedule.status === "running" ? '#ff8544' : null,
|
|
||||||
}}
|
}}
|
||||||
color={schedule.status === "running" ? "secondary" : "primary"}
|
color={schedule.status === "running" ? "secondary" : "primary"}
|
||||||
variant={schedule.status === "running" ? "contained" : "outlined"}
|
variant={schedule.status === "running" ? "contained" : "outlined"}
|
||||||
@@ -725,23 +726,23 @@ const SchedulesTab = memo((props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: 50, marginBottom: 20 }}>
|
<div style={{ marginTop: 50, marginBottom: 20 }}>
|
||||||
<h4 style={{color: "#FFFFFF"}} >Webhooks</h4>
|
<Typography variant='h6' color="textPrimary">Webhooks</Typography>
|
||||||
<span> Webhooks used in Shuffle workflows.
|
<Typography variant='body2' color="textSecondary"> Webhooks used in Shuffle workflows.
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/triggers#webhooks"
|
href="/docs/triggers#webhooks"
|
||||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
style={{ color: theme.palette.primary.main }}
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -757,7 +758,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
minWidth: 600,
|
minWidth: 600,
|
||||||
}}>
|
}}>
|
||||||
<ListItem style={{width:"100%", borderBottom:"1px solid #494949", display: "table-row"}}>
|
<ListItem style={{width:"100%", borderBottom:theme.palette.defaultBorder, display: "table-row"}}>
|
||||||
{["Name", "Environment", "Workflow", "URL", "Action"].map((header, index) => (
|
{["Name", "Environment", "Workflow", "URL", "Action"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
key={index}
|
key={index}
|
||||||
@@ -767,7 +768,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -779,7 +780,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
key={rowIndex}
|
key={rowIndex}
|
||||||
style={{
|
style={{
|
||||||
display: "table-row",
|
display: "table-row",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(5)
|
{Array(5)
|
||||||
@@ -796,7 +797,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
height: "20px",
|
height: "20px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
@@ -808,13 +809,13 @@ const SchedulesTab = memo((props) => {
|
|||||||
):(
|
):(
|
||||||
webHooks?.length === 0 ? (
|
webHooks?.length === 0 ? (
|
||||||
<div style={{textAlign: "center"}}>
|
<div style={{textAlign: "center"}}>
|
||||||
<Typography style={{color: "#FFFFFF", padding: 20, fontSize: 16, textAlign: 'center'}}>No webhooks found</Typography>
|
<Typography style={{color: theme.palette.text.primary, padding: 20, fontSize: 16, textAlign: 'center'}}>No webhooks found</Typography>
|
||||||
</div>
|
</div>
|
||||||
):(
|
):(
|
||||||
webHooks.map((webhook, index) => {
|
webHooks.map((webhook, index) => {
|
||||||
var bgColor = "#212121"
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = "#1a1a1a";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -840,7 +841,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
style={{
|
style={{
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
color: "#f85a3e",
|
color: theme.palette.primary.main,
|
||||||
}}
|
}}
|
||||||
href={`/workflows/${webhook.workflows[0]}`}
|
href={`/workflows/${webhook.workflows[0]}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -853,7 +854,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
webhook.workflows[0].workflow_id !== "global"
|
webhook.workflows[0].workflow_id !== "global"
|
||||||
? "#FF8444"
|
? theme.palette.primary.main
|
||||||
: "grey",
|
: "grey",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -904,6 +905,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color:webhook.status === "running" ? '#1a1a1a' : null,
|
color:webhook.status === "running" ? '#1a1a1a' : null,
|
||||||
backgroundColor: webhook.status === "running" ? '#ff8544' : null,
|
backgroundColor: webhook.status === "running" ? '#ff8544' : null,
|
||||||
|
width: 150,
|
||||||
}}
|
}}
|
||||||
color={webhook.status === "running" ? "secondary" : "primary"}
|
color={webhook.status === "running" ? "secondary" : "primary"}
|
||||||
variant={webhook.status === "running" ? "contained" : "outlined"}
|
variant={webhook.status === "running" ? "contained" : "outlined"}
|
||||||
@@ -928,24 +930,24 @@ const SchedulesTab = memo((props) => {
|
|||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: 50, marginBottom: 20 }}>
|
<div style={{ marginTop: 50, marginBottom: 20 }}>
|
||||||
<h4 style={{color: "#FFFFFF"}}>Pipelines</h4>
|
<Typography variant='h6' color="textPrimary" >Pipelines</Typography>
|
||||||
|
|
||||||
<span>
|
<Typography variant='body2' color="textSecondary" >
|
||||||
Controls Pipelines on your Orborus Runners, e.g. for Log Ingestion, MQ subscriptions or Sigma Detections.{" "}
|
Controls Pipelines on your Orborus Runners, e.g. for Log Ingestion, MQ subscriptions or Sigma Detections.{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/triggers#pipelines"
|
href="/docs/triggers#pipelines"
|
||||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
style={{ color: theme.palette.primary.main }}
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
|
|
||||||
<div style={{marginBottom: 10, marginTop: 10, }}/>
|
<div style={{marginBottom: 10, marginTop: 10, }}/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style={{ backgroundColor: '#ff8544', color: "#1a1a1a", borderRadius: 4, textTransform: "capitalize", fontSize: 16, }}
|
style={{ borderRadius: 4, textTransform: "capitalize", fontSize: 16, }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => setPipelineModalOpen(true)}
|
onClick={() => setPipelineModalOpen(true)}
|
||||||
@@ -958,7 +960,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: pipelines?.length === 0 ? "hidden" : "auto",
|
overflowX: pipelines?.length === 0 ? "hidden" : "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -974,7 +976,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0
|
paddingBottom: 0
|
||||||
}}>
|
}}>
|
||||||
<ListItem style={{width:"100%", borderBottom:"1px solid #494949", display: "table-row"}}>
|
<ListItem style={{width:"100%", borderBottom:theme.palette.defaultBorder, display: "table-row"}}>
|
||||||
{["Command", "Environment", "Total Runs", "Actions"].map((header, index) => (
|
{["Command", "Environment", "Total Runs", "Actions"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
key={index}
|
key={index}
|
||||||
@@ -984,7 +986,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -997,7 +999,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
key={rowIndex}
|
key={rowIndex}
|
||||||
style={{
|
style={{
|
||||||
display: "table-row",
|
display: "table-row",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(5)
|
{Array(5)
|
||||||
@@ -1015,7 +1017,7 @@ const SchedulesTab = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
height: "20px",
|
height: "20px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
@@ -1031,14 +1033,14 @@ const SchedulesTab = memo((props) => {
|
|||||||
): (
|
): (
|
||||||
pipelines?.length === 0 ? (
|
pipelines?.length === 0 ? (
|
||||||
<div style={{width: "100%", textAlign: "center", }}>
|
<div style={{width: "100%", textAlign: "center", }}>
|
||||||
<Typography style={{color: "#FFFFFF", padding: 20,width: "100%", fontSize: 16, textAlign: 'center'}}>No pipeline trigger found</Typography>
|
<Typography style={{color: theme.palette.text.primary, padding: 20,width: "100%", fontSize: 16, textAlign: 'center'}}>No pipeline trigger found</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
):(
|
):(
|
||||||
pipelines.map((pipeline, index) => {
|
pipelines.map((pipeline, index) => {
|
||||||
var bgColor = "#212121"
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = "#1a1a1a";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1094,4 +1096,3 @@ const SchedulesTab = memo((props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default SchedulesTab;
|
export default SchedulesTab;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useRef, useContext } from 'react';
|
import React, { useState, useEffect, useRef, useContext } from 'react';
|
||||||
|
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
@@ -47,16 +47,19 @@ const chipStyle = {
|
|||||||
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
|
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const SearchData = props => {
|
const SearchData = props => {
|
||||||
const { serverside, globalUrl, userdata } = props
|
const { serverside, globalUrl, userdata } = props
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const { searchBarModalOpen, setSearchBarModalOpen } = useContext(Context);
|
const { searchBarModalOpen, setSearchBarModalOpen, isDocSearchModalOpen } = useContext(Context);
|
||||||
const borderRadius = 3
|
const borderRadius = 3
|
||||||
const node = useRef()
|
const node = useRef()
|
||||||
const [searchOpen, setSearchOpen] = useState(false)
|
const [searchOpen, setSearchOpen] = useState(false)
|
||||||
const [oldPath, setOldPath] = useState("")
|
const [oldPath, setOldPath] = useState("")
|
||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
|
const isDocSearchModal = isDocSearchModalOpen;
|
||||||
|
const {themeMode, supportEmail} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const handleLinkClick = () => {
|
const handleLinkClick = () => {
|
||||||
if (searchBarModalOpen) {
|
if (searchBarModalOpen) {
|
||||||
@@ -90,6 +93,8 @@ const SearchData = props => {
|
|||||||
const [inputValue, setInputValue] = useState(currentRefinement);
|
const [inputValue, setInputValue] = useState(currentRefinement);
|
||||||
|
|
||||||
const textFieldRef = useRef(null);
|
const textFieldRef = useRef(null);
|
||||||
|
const debounceTimeoutRef = useRef(null);
|
||||||
|
|
||||||
const keyPressHandler = (e) => {
|
const keyPressHandler = (e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -110,10 +115,25 @@ const SearchData = props => {
|
|||||||
}, [searchOpen]);
|
}, [searchOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentRefinement !== inputValue) {
|
// Clear any existing timeout to prevent multiple executions
|
||||||
refine(inputValue);
|
if (debounceTimeoutRef.current) {
|
||||||
|
clearTimeout(debounceTimeoutRef.current);
|
||||||
}
|
}
|
||||||
}, [currentRefinement]);
|
|
||||||
|
// Set a new timeout that will execute the search after a 200ms delay
|
||||||
|
debounceTimeoutRef.current = setTimeout(() => {
|
||||||
|
refine(inputValue);
|
||||||
|
setSearchOpen(inputValue.trim() !== '');
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
// Cleanup function that runs when component unmounts or when dependencies change
|
||||||
|
// This ensures we don't have any hanging timeouts
|
||||||
|
return () => {
|
||||||
|
if (debounceTimeoutRef.current) {
|
||||||
|
clearTimeout(debounceTimeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [inputValue, refine]); // Effect runs when inputValue or refine function changes
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
@@ -122,14 +142,13 @@ const SearchData = props => {
|
|||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
style={{ zIndex: 1100, marginTop: -20, marginBottom: 200, position: "fixed", backgroundColor: theme.palette.inputColor, borderRadius: borderRadius, width: 685, }}
|
style={{ zIndex: 1100, marginTop: -20, marginBottom: 200, position: "fixed", backgroundColor: theme.palette.textFieldStyle.backgroundColor, borderRadius: borderRadius, width: 690, }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
height: 50,
|
height: 50,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
fontSize: "0.9em",
|
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
},
|
},
|
||||||
disableUnderline: true,
|
disableUnderline: true,
|
||||||
@@ -149,7 +168,7 @@ const SearchData = props => {
|
|||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
type="search"
|
type="search"
|
||||||
color="primary"
|
color="primary"
|
||||||
placeholder="Find Public Apps, Workflows, Documentation..."
|
placeholder={isDocSearchModal ? "Type to search documentation..." : "Find Public Apps, Workflows, Documentation..."}
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
id="shuffle_search_field"
|
id="shuffle_search_field"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
@@ -163,12 +182,6 @@ const SearchData = props => {
|
|||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
const newValue = event.target.value;
|
const newValue = event.target.value;
|
||||||
setInputValue(newValue);
|
setInputValue(newValue);
|
||||||
refine(newValue);
|
|
||||||
if (newValue.trim() !== '') {
|
|
||||||
setSearchOpen(true);
|
|
||||||
} else {
|
|
||||||
setSearchOpen(false);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
onKeyDown={keyPressHandler}
|
onKeyDown={keyPressHandler}
|
||||||
inputRef={textFieldRef}
|
inputRef={textFieldRef}
|
||||||
@@ -205,12 +218,12 @@ const SearchData = props => {
|
|||||||
const baseImage = <CodeIcon />
|
const baseImage = <CodeIcon />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 75, boxShadows: "none", }}>
|
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: theme.palette.text.primary, zIndex: 1002, backgroundColor: theme.palette.textFieldStyle.backgroundColor, width: "100%", left: 75, boxShadows: "none", }}>
|
||||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 105 }}>
|
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 105 }}>
|
||||||
Workflows
|
Workflows
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
<List style={{ backgroundColor: themeMode === "dark" ? "#2A2A2A" : "#F5F5F5", }}>
|
||||||
{hits.length === 0 ?
|
{hits.length === 0 ?
|
||||||
<ListItem style={outerlistitemStyle}>
|
<ListItem style={outerlistitemStyle}>
|
||||||
<ListItemAvatar onClick={() => console.log(hits)}>
|
<ListItemAvatar onClick={() => console.log(hits)}>
|
||||||
@@ -230,7 +243,7 @@ const SearchData = props => {
|
|||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
overflowY: "hidden",
|
overflowY: "hidden",
|
||||||
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
||||||
backgroundColor: mouseHoverIndex === index ? "#1f2023" : "inherit",
|
backgroundColor: mouseHoverIndex === index ? theme.palette.hoverColor : "inherit",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
marginLeft: 5,
|
marginLeft: 5,
|
||||||
marginRight: 5,
|
marginRight: 5,
|
||||||
@@ -384,14 +397,14 @@ const SearchData = props => {
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
toast(`Failed to ${type} the app for your organization. Please try again or contact support@shuffler.io`)
|
toast(`Failed to ${type} the app for your organization. Please try again or contact ${supportEmail}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json()
|
return response.json()
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
toast(`Failed to ${type} the app for your organization. Please try again or contact support@shuffler.io for more info`)
|
toast(`Failed to ${type} the app for your organization. Please try again or contact ${supportEmail} for more info`)
|
||||||
} else {
|
} else {
|
||||||
toast(`App successfully ${type}d. It may now be used in your workflows.`)
|
toast(`App successfully ${type}d. It may now be used in your workflows.`)
|
||||||
}
|
}
|
||||||
@@ -426,7 +439,7 @@ const SearchData = props => {
|
|||||||
const baseImage = <LibraryBooksIcon />
|
const baseImage = <LibraryBooksIcon />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card elevation={0} style={{ marginRight: 10, color: "white", zIndex: 999, backgroundColor: theme.palette.inputColor, width: 685, boxShadows: "none", }}>
|
<Card elevation={0} style={{ marginRight: 10, color: "white", zIndex: 999, backgroundColor: theme.palette.textFieldStyle.backgroundColor, width: 685, boxShadows: "none", }}>
|
||||||
{/* <IconButton style={{ zIndex: 5000, position: "absolute", right: 14, color: "grey" }} onClick={() => {
|
{/* <IconButton style={{ zIndex: 5000, position: "absolute", right: 14, color: "grey" }} onClick={() => {
|
||||||
setSearchOpen(false)
|
setSearchOpen(false)
|
||||||
}}>
|
}}>
|
||||||
@@ -436,7 +449,7 @@ const SearchData = props => {
|
|||||||
Apps
|
Apps
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
<List style={{ backgroundColor: themeMode === "dark" ? "#2A2A2A" : "#F5F5F5", }}>
|
||||||
{hits.length === 0 ?
|
{hits.length === 0 ?
|
||||||
<ListItem style={outerlistitemStyle}>
|
<ListItem style={outerlistitemStyle}>
|
||||||
<ListItemAvatar onClick={() => console.log(hits)}>
|
<ListItemAvatar onClick={() => console.log(hits)}>
|
||||||
@@ -456,7 +469,7 @@ const SearchData = props => {
|
|||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
overflowY: "hidden",
|
overflowY: "hidden",
|
||||||
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
||||||
backgroundColor: mouseHoverIndex === index ? "#1f2023" : "inherit",
|
backgroundColor: mouseHoverIndex === index ? theme.palette.hoverColor : "inherit",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
marginLeft: 5,
|
marginLeft: 5,
|
||||||
marginRight: 5,
|
marginRight: 5,
|
||||||
@@ -605,7 +618,11 @@ const SearchData = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hits.length > 4) {
|
if (hits.length > 4) {
|
||||||
hits = hits.slice(0, 4)
|
if(!isDocSearchModal) {
|
||||||
|
hits = hits.slice(0, 4)
|
||||||
|
} else {
|
||||||
|
hits = hits.slice(0, 15)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const type = "documentation"
|
const type = "documentation"
|
||||||
@@ -614,15 +631,19 @@ const SearchData = props => {
|
|||||||
//console.log(type, hits.length, hits)
|
//console.log(type, hits.length, hits)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 470, boxShadows: "none", }}>
|
<Card elevation={0} style={{ marginRight: 10, marginTop: isDocSearchModal ? 0 : 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.textFieldStyle.backgroundColor, width: "100%", left: 470, boxShadows: "none", }}>
|
||||||
{/* <IconButton style={{ zIndex: 5000, position: "absolute", right: 14, color: "grey" }} onClick={() => {
|
{/* <IconButton style={{ zIndex: 5000, position: "absolute", right: 14, color: "grey" }} onClick={() => {
|
||||||
setSearchOpen(false)
|
setSearchOpen(false)
|
||||||
}}>
|
}}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton> */}
|
</IconButton> */}
|
||||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 152 }}>
|
{
|
||||||
Documentation
|
!isDocSearchModal && (
|
||||||
</Typography>
|
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 152 }}>
|
||||||
|
Documentation
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
}
|
||||||
{/*
|
{/*
|
||||||
<IconButton edge="end" aria-label="delete" style={{position: "absolute", top: 5, right: 15,}} onClick={() => {
|
<IconButton edge="end" aria-label="delete" style={{position: "absolute", top: 5, right: 15,}} onClick={() => {
|
||||||
setSearchOpen(false)
|
setSearchOpen(false)
|
||||||
@@ -630,7 +651,7 @@ const SearchData = props => {
|
|||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
*/}
|
*/}
|
||||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
<List style={{ backgroundColor: themeMode === "dark" ? "#2A2A2A" : "#F5F5F5", marginTop: isDocSearchModal ? 35 : 0, }}>
|
||||||
{hits.length === 0 ?
|
{hits.length === 0 ?
|
||||||
<ListItem style={outerlistitemStyle}>
|
<ListItem style={outerlistitemStyle}>
|
||||||
<ListItemAvatar onClick={() => console.log(hits)}>
|
<ListItemAvatar onClick={() => console.log(hits)}>
|
||||||
@@ -650,12 +671,12 @@ const SearchData = props => {
|
|||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
overflowY: "hidden",
|
overflowY: "hidden",
|
||||||
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
||||||
backgroundColor: mouseHoverIndex === index ? "#1f2023" : "inherit",
|
backgroundColor: mouseHoverIndex === index ? theme.palette.hoverColor : "inherit",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
marginLeft: 5,
|
marginLeft: 5,
|
||||||
marginRight: 5,
|
marginRight: 5,
|
||||||
maxHeight: 75,
|
maxHeight: isDocSearchModal ? 100 : 75,
|
||||||
minHeight: 75,
|
minHeight: isDocSearchModal ? 100 : 75,
|
||||||
maxWidth: 420,
|
maxWidth: 420,
|
||||||
minWidth: "100%",
|
minWidth: "100%",
|
||||||
}
|
}
|
||||||
@@ -666,9 +687,13 @@ const SearchData = props => {
|
|||||||
(hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
|
(hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
|
||||||
|
|
||||||
if (name.length > 30) {
|
if (name.length > 30) {
|
||||||
name = name.slice(0, 30) + "..."
|
if(isDocSearchModal) {
|
||||||
|
name = name.slice(0, 70) + "..."
|
||||||
|
} else {
|
||||||
|
name = name.slice(0, 30) + "..."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const secondaryText = hit.data !== undefined ? hit.data.slice(0, 40) + "..." : ""
|
const secondaryText = hit.data !== undefined ? hit.data.slice(0, 80) + "..." : ""
|
||||||
const avatar = hit.image_url === undefined ?
|
const avatar = hit.image_url === undefined ?
|
||||||
baseImage
|
baseImage
|
||||||
:
|
:
|
||||||
@@ -719,7 +744,7 @@ const SearchData = props => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={name}
|
primary={name}
|
||||||
secondary={secondaryText}
|
secondary={<div style={{ padding: '8px 0' }}>{secondaryText}</div>}
|
||||||
/>
|
/>
|
||||||
{/*
|
{/*
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
@@ -763,13 +788,20 @@ const SearchData = props => {
|
|||||||
window.open(modifiedUrl, '_blank');
|
window.open(modifiedUrl, '_blank');
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 470, boxShadows: "none", }}>
|
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.textFieldStyle.backgroundColor, width: "100%", left: 470, boxShadows: "none", }}>
|
||||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 152 }}>
|
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 152 }}>
|
||||||
Discord Chat
|
Discord Chat
|
||||||
</Typography>
|
</Typography>
|
||||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
<List style={{ backgroundColor: themeMode === "dark" ? "#2A2A2A" : "#F5F5F5", }}>
|
||||||
{hits.length === 0 ?
|
{hits.length === 0 ?
|
||||||
<ListItem style={outerlistitemStyle}>
|
<ListItem
|
||||||
|
sx={{
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={outerlistitemStyle}
|
||||||
|
>
|
||||||
<ListItemAvatar onClick={() => console.log(hits)}>
|
<ListItemAvatar onClick={() => console.log(hits)}>
|
||||||
<Avatar>
|
<Avatar>
|
||||||
<FolderIcon />
|
<FolderIcon />
|
||||||
@@ -781,7 +813,11 @@ const SearchData = props => {
|
|||||||
/>
|
/>
|
||||||
</ListItem>:
|
</ListItem>:
|
||||||
hits.map((chat, index) => (
|
hits.map((chat, index) => (
|
||||||
<ListItem onClick={() => handleHitClick(chat.url)} key={index} style={{ cursor: "pointer", borderBottom: "1px solid rgba(255,255,255,0.4)" }} onMouseOver={() => setMouseHoverIndex(index)}>
|
<ListItem sx={{
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor
|
||||||
|
}
|
||||||
|
}} onClick={() => handleHitClick(chat.url)} key={index} style={{ cursor: "pointer", borderBottom: "1px solid rgba(255,255,255,0.4)" }} onMouseOver={() => setMouseHoverIndex(index)}>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Avatar src="/discord-logo.png" />
|
<Avatar src="/discord-logo.png" />
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
@@ -897,28 +933,38 @@ const SearchData = props => {
|
|||||||
|
|
||||||
const modalView = (
|
const modalView = (
|
||||||
<div>
|
<div>
|
||||||
<Grid container style={{ display: "contents", }}>
|
{
|
||||||
<Grid item xs="auto" style={{}}>
|
!isDocSearchModal ? (
|
||||||
<Index indexName="appsearch">
|
<Grid container style={{ display: "contents", }}>
|
||||||
<CustomAppHits />
|
<Grid item xs="auto" style={{}}>
|
||||||
</Index>
|
<Index indexName="appsearch">
|
||||||
|
<CustomAppHits />
|
||||||
|
</Index>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs="auto" style={{}}>
|
||||||
|
<Index indexName="workflows">
|
||||||
|
<CustomWorkflowHits />
|
||||||
|
</Index>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs="auto" style={{}}>
|
||||||
|
<Index indexName="documentation">
|
||||||
|
<CustomDocHits />
|
||||||
|
</Index>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs="auto" style={{}}>
|
||||||
|
<Index indexName="discord_chat">
|
||||||
|
<CustomDiscordHits />
|
||||||
|
</Index>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs="auto" style={{}}>
|
) : (
|
||||||
<Index indexName="workflows">
|
<Grid item xs="auto" style={{width: "100%"}}>
|
||||||
<CustomWorkflowHits />
|
<Index indexName="documentation">
|
||||||
</Index>
|
<CustomDocHits />
|
||||||
</Grid>
|
</Index>
|
||||||
<Grid item xs="auto" style={{}}>
|
</Grid>
|
||||||
<Index indexName="documentation">
|
)
|
||||||
<CustomDocHits />
|
}
|
||||||
</Index>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs="auto" style={{}}>
|
|
||||||
<Index indexName="discord_chat">
|
|
||||||
<CustomDiscordHits />
|
|
||||||
</Index>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -932,7 +978,7 @@ const SearchData = props => {
|
|||||||
<CustomSearchBox />
|
<CustomSearchBox />
|
||||||
{modalView}
|
{modalView}
|
||||||
</InstantSearch>
|
</InstantSearch>
|
||||||
{gettingStartData}
|
{!isDocSearchModal && gettingStartData}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useRef, useContext } from 'react';
|
import React, { useState, useEffect, useRef, useContext } from 'react';
|
||||||
|
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||||
import SearchBox from "../components/SearchData.jsx";
|
import SearchBox from "../components/SearchData.jsx";
|
||||||
|
|
||||||
@@ -46,7 +46,8 @@ const chipStyle = {
|
|||||||
|
|
||||||
const SearchField = props => {
|
const SearchField = props => {
|
||||||
const { serverside, userdata, isMobile, isLoaded, globalUrl, isHeader, isLoggedIn, small, rounded } = props
|
const { serverside, userdata, isMobile, isLoaded, globalUrl, isHeader, isLoggedIn, small, rounded } = props
|
||||||
|
const {themeMode} = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode);
|
||||||
const {searchBarModalOpen, setSearchBarModalOpen} = useContext(Context);
|
const {searchBarModalOpen, setSearchBarModalOpen} = useContext(Context);
|
||||||
|
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
@@ -87,7 +88,7 @@ const SearchField = props => {
|
|||||||
height: 785,
|
height: 785,
|
||||||
borderRadius: 16,
|
borderRadius: 16,
|
||||||
border: "1px solid var(--Container-Stroke, #494949)",
|
border: "1px solid var(--Container-Stroke, #494949)",
|
||||||
background: "var(--Container, #000000)",
|
background: theme.palette.DialogStyle.backgroundColor,
|
||||||
boxShadow: "0px 16px 24px 8px rgba(0, 0, 0, 0.25)",
|
boxShadow: "0px 16px 24px 8px rgba(0, 0, 0, 0.25)",
|
||||||
zIndex: 13000,
|
zIndex: 13000,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useState, useEffect, useLayoutEffect, } from 'react';
|
import React, { useRef, useState, useEffect, useLayoutEffect, useContext } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import '../codeeditor-index.css';
|
import '../codeeditor-index.css';
|
||||||
import {
|
import {
|
||||||
@@ -17,8 +17,8 @@ import {
|
|||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
Collapse,
|
Collapse,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
import { Context } from '../context/ContextApi.jsx';
|
||||||
import theme from '../theme.jsx';
|
import {getTheme} from '../theme.jsx';
|
||||||
import Checkbox from '@mui/material/Checkbox';
|
import Checkbox from '@mui/material/Checkbox';
|
||||||
import { isMobile } from "react-device-detect"
|
import { isMobile } from "react-device-detect"
|
||||||
import { NestedMenuItem } from "mui-nested-menu"
|
import { NestedMenuItem } from "mui-nested-menu"
|
||||||
@@ -46,6 +46,7 @@ import {
|
|||||||
DragIndicator as DragIndicatorIcon,
|
DragIndicator as DragIndicatorIcon,
|
||||||
RestartAlt as RestartAltIcon,
|
RestartAlt as RestartAltIcon,
|
||||||
ArrowForward as ArrowForwardIcon,
|
ArrowForward as ArrowForwardIcon,
|
||||||
|
KeyboardReturn as KeyboardReturnIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ import AceEditor from "react-ace";
|
|||||||
import ace from "ace-builds";
|
import ace from "ace-builds";
|
||||||
import 'ace-builds/src-noconflict/mode-python';
|
import 'ace-builds/src-noconflict/mode-python';
|
||||||
import 'ace-builds/src-noconflict/mode-json';
|
import 'ace-builds/src-noconflict/mode-json';
|
||||||
|
import 'ace-builds/src-noconflict/mode-yaml';
|
||||||
//import 'ace-builds/src-noconflict/theme-twilight';
|
//import 'ace-builds/src-noconflict/theme-twilight';
|
||||||
//import 'ace-builds/src-noconflict/theme-solarized_dark';
|
//import 'ace-builds/src-noconflict/theme-solarized_dark';
|
||||||
import 'ace-builds/src-noconflict/theme-gruvbox';
|
import 'ace-builds/src-noconflict/theme-gruvbox';
|
||||||
@@ -89,13 +91,17 @@ const liquidFilters = [
|
|||||||
const pythonFilters = [
|
const pythonFilters = [
|
||||||
{ "name": "Hello World", "value": `print("hello world")`, "example": `` },
|
{ "name": "Hello World", "value": `print("hello world")`, "example": `` },
|
||||||
{ "name": "Using Shuffle variables", "value": `import json\nnodevalue = r\"\"\"$exec\"\"\"\nif not nodevalue:\n nodevalue = r\"\"\"{\"sample\": \"string\", \"int\": 1}\"\"\"\n \njsondata = json.loads(nodevalue)\nprint(jsondata)`, "example": `` },
|
{ "name": "Using Shuffle variables", "value": `import json\nnodevalue = r\"\"\"$exec\"\"\"\nif not nodevalue:\n nodevalue = r\"\"\"{\"sample\": \"string\", \"int\": 1}\"\"\"\n \njsondata = json.loads(nodevalue)\nprint(jsondata)`, "example": `` },
|
||||||
|
{ "name": "Filter a list", "value": `import json\nnodevalue = r\"\"\"$exec\"\"\"\nif not nodevalue:\n nodevalue = r\"\"\"[{\"sample\": \"string\", \"int\": 1, "malicious": "no"}, {\"sample\": \"string2\", \"int\": 1, "malicious": "yes"}]\"\"\"\n \njsondata = json.loads(nodevalue)\nfiltered = []\nfor item in jsondata:\n try:\n if item[\"malicious\"] == \"yes\":\n filtered.append(item)\n except:\n pass\nprint(json.dumps(filtered))`, "example": `` },
|
||||||
{ "name": "Print Execution ID", "value": `print(self.current_execution_id)`, "example": `` },
|
{ "name": "Print Execution ID", "value": `print(self.current_execution_id)`, "example": `` },
|
||||||
{ "name": "Get full execution details", "value": `print(self.full_execution)`, "example": `` },
|
{ "name": "Get full execution details", "value": `print(self.full_execution)`, "example": `` },
|
||||||
{ "name": "Use files", "value": `# Create a sample file\nfiles = [{\n \"filename\": \"test.txt\",\n \"data\": \"Testdata\"\n}]\nret = self.set_files(files)\n\n# Get the content of the file from Shuffle storage\n# Originally a byte string in the \"data\" key\nfile_content = (self.get_file(ret[0])[\"data\"]).decode()\nprint(file_content)`, "example": `` },
|
{ "name": "Use files", "value": `# Create a sample file\nfiles = [{\n \"filename\": \"test.txt\",\n \"data\": \"Testdata\"\n}]\nret = self.set_files(files)\n\n# Get the content of the file from Shuffle storage\n# Originally a byte string in the \"data\" key\nfile_content = (self.get_file(ret[0])[\"data\"]).decode()\nprint(file_content)`, "example": `` },
|
||||||
|
|
||||||
{ "name": "Use datastore", "value": `key = \"testkey\"\nvalue = \"The value of the testkey\"\n\nself.set_cache(key, value)\n\n# Print the details of the key after it's been updated\n# To get the value, use self.get_cache(key)[\"value\"]\nprint(self.get_cache(key))`, "example": `` },
|
{ "name": "Use datastore", "value": `key = \"testkey\"\nvalue = \"The value of the testkey\"\n\nself.set_key(key, value)\n\n# Print the details of the key after it's been updated\n# To get the value, use self.get_key(key)[\"value\"]\nprint(self.get_key(key))`, "example": `` },
|
||||||
{ "name": "Run an App Action", "value": `response = shuffle.run_app(app_id="app", action="action_name", auth="authentication_id", params={})\nprint(response)`, "example": ``, "disabled": true, },
|
|
||||||
{ "name": "Run a Singul AI Action", "value": `response = singul.create_ticket(app="jira/iris/ticketingsystem", fields={"title": "Test ticket!"})\nprint(response)`, "example": ``, "disabled": true, },
|
{ "name": "Run a Subflow", "value": `response = shuffle.run_workflow(workflow_id="", start_command="Runtime arg here!", wait=True)\nprint(response)`, "example": ``, "disabled": false, },
|
||||||
|
{ "name": "Run an App Action", "value": `response = shuffle.run_app(app_id="app", action="action_name", auth="authentication_id", params={})\nprint(response)`, "example": ``, "disabled": false, },
|
||||||
|
{ "name": "Run a Singul AI Action", "value": `response = singul.cases.create_ticket(app="jira", fields={"title": "Test ticket!"})\nprint(response)`, "example": ``, "disabled": false, },
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -114,6 +120,7 @@ const CodeEditor = (props) => {
|
|||||||
handleActionParamChange,
|
handleActionParamChange,
|
||||||
setcodedata,
|
setcodedata,
|
||||||
isFileEditor,
|
isFileEditor,
|
||||||
|
isWorkflowEditor,
|
||||||
runUpdateText,
|
runUpdateText,
|
||||||
toolsAppId,
|
toolsAppId,
|
||||||
parameterName,
|
parameterName,
|
||||||
@@ -127,7 +134,7 @@ const CodeEditor = (props) => {
|
|||||||
fieldname,
|
fieldname,
|
||||||
contentLoading,
|
contentLoading,
|
||||||
editorData,
|
editorData,
|
||||||
handleSubflowParamChange,
|
handleTriggerParamChange,
|
||||||
setAiQueryModalOpen,
|
setAiQueryModalOpen,
|
||||||
fullScreenMode,
|
fullScreenMode,
|
||||||
environment,
|
environment,
|
||||||
@@ -138,12 +145,9 @@ const CodeEditor = (props) => {
|
|||||||
|
|
||||||
const [localcodedata, setlocalcodedata] = React.useState(codedata === undefined || codedata === null || codedata.length === 0 ? "" : codedata);
|
const [localcodedata, setlocalcodedata] = React.useState(codedata === undefined || codedata === null || codedata.length === 0 ? "" : codedata);
|
||||||
|
|
||||||
//const { setContainer } = useCodeMirror({
|
|
||||||
// container: editorRef.current,
|
|
||||||
// extensions,
|
|
||||||
// value: localcodedata,
|
|
||||||
//})
|
|
||||||
// const {codelang, setcodelang} = props
|
// const {codelang, setcodelang} = props
|
||||||
|
const {themeMode, supportEmail} = useContext(Context)
|
||||||
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
const [validation, setValidation] = React.useState(false);
|
const [validation, setValidation] = React.useState(false);
|
||||||
const [expOutput, setExpOutput] = React.useState(" ");
|
const [expOutput, setExpOutput] = React.useState(" ");
|
||||||
@@ -205,7 +209,7 @@ const CodeEditor = (props) => {
|
|||||||
const triggerField = searchParams.get('trigger_field');
|
const triggerField = searchParams.get('trigger_field');
|
||||||
const triggerName = searchParams.get('trigger_name');
|
const triggerName = searchParams.get('trigger_name');
|
||||||
const conditionId = searchParams.get('condition_id');
|
const conditionId = searchParams.get('condition_id');
|
||||||
const conditionField = searchParams.get('field');
|
const conditionField = searchParams.get('condition_field');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (actionId === undefined || actionId === null) {
|
if (actionId === undefined || actionId === null) {
|
||||||
@@ -244,7 +248,7 @@ const CodeEditor = (props) => {
|
|||||||
setSelectedCondition(condition);
|
setSelectedCondition(condition);
|
||||||
// Update available variables when condition changes
|
// Update available variables when condition changes
|
||||||
updateAvailableVariables(actionlist);
|
updateAvailableVariables(actionlist);
|
||||||
}, [conditionId, fieldName])
|
}, [conditionId, conditionField])
|
||||||
|
|
||||||
// Extract variable updating logic into a separate function
|
// Extract variable updating logic into a separate function
|
||||||
const updateAvailableVariables = (actionlist) => {
|
const updateAvailableVariables = (actionlist) => {
|
||||||
@@ -298,8 +302,19 @@ const CodeEditor = (props) => {
|
|||||||
setMainVariables(tmpVariables)
|
setMainVariables(tmpVariables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
const tryItButton = document.getElementById("try-it-button")
|
||||||
|
if (tryItButton !== undefined && tryItButton !== null) {
|
||||||
|
tryItButton.click()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the original useEffect for actionlist since we'll update on action/trigger changes
|
// Remove the original useEffect for actionlist since we'll update on action/trigger changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
document.addEventListener("keydown", handleKeyDown)
|
||||||
updateAvailableVariables(actionlist)
|
updateAvailableVariables(actionlist)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -886,6 +901,8 @@ const CodeEditor = (props) => {
|
|||||||
// Whelp this is inefficient af. Single loop pls
|
// Whelp this is inefficient af. Single loop pls
|
||||||
// When the found array is empty.
|
// When the found array is empty.
|
||||||
if (found !== null && found !== undefined) {
|
if (found !== null && found !== undefined) {
|
||||||
|
|
||||||
|
//console.log("FOUND: ", found)
|
||||||
try {
|
try {
|
||||||
for (var i = 0; i < found.length; i++) {
|
for (var i = 0; i < found.length; i++) {
|
||||||
try {
|
try {
|
||||||
@@ -921,27 +938,71 @@ const CodeEditor = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the location to ensure replacements happen correctly
|
||||||
|
var foundlocation = -1
|
||||||
|
for (var j = 0; j < input.length; j++) {
|
||||||
|
const foundStringSize = fixedVariable.length
|
||||||
|
const foundslice = input.slice(j, j + foundStringSize)
|
||||||
|
//console.log("FOUNDSLICE: ", foundslice)
|
||||||
|
if (fixedVariable !== foundslice) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it matches EXACTLY or not, as there may be more AFTER the found[i]
|
||||||
|
const nextchar = input.slice(j + foundStringSize, j + foundStringSize + 1)
|
||||||
|
if (nextchar === ".") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
foundlocation = j
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: There is something wrong here with:
|
||||||
|
// $variable.#
|
||||||
|
// vs
|
||||||
|
// $variable.#.subvalue
|
||||||
|
// if you put both of those lines in the same editor, then it will replace both (somehow). Make sure $variable.#.subvalue exists while testing.
|
||||||
|
console.log("FOUNDLOC: ", fixedVariable, foundlocation)
|
||||||
for (var j = 0; j < actionlist.length; j++) {
|
for (var j = 0; j < actionlist.length; j++) {
|
||||||
if (fixedVariable.slice(1,).toLowerCase() !== actionlist[j].autocomplete.toLowerCase()) {
|
if (fixedVariable.slice(1,).toLowerCase() !== actionlist[j].autocomplete.toLowerCase()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look for the location of found[i] in the input, as to make sure to skip parts of the input in the replace. Find ALL spots for it
|
||||||
valuefound = true
|
valuefound = true
|
||||||
|
var newvalue = ""
|
||||||
try {
|
try {
|
||||||
if (typeof actionlist[j].example === "object") {
|
|
||||||
|
|
||||||
input = input.replace(found[i], JSON.stringify(actionlist[j].example), -1);
|
if (typeof actionlist[j].example === "object") {
|
||||||
|
newvalue = JSON.stringify(actionlist[j].example)
|
||||||
|
|
||||||
} else if (actionlist[j].example.trim().startsWith("{") || actionlist[j].example.trim().startsWith("[")) {
|
} else if (actionlist[j].example.trim().startsWith("{") || actionlist[j].example.trim().startsWith("[")) {
|
||||||
input = input.replace(found[i], JSON.stringify(actionlist[j].example), -1);
|
|
||||||
|
newvalue = JSON.stringify(actionlist[j].example)
|
||||||
} else {
|
} else {
|
||||||
const newExample = fixStringInput(actionlist[j].example)
|
const newExample = fixStringInput(actionlist[j].example)
|
||||||
input = input.replace(found[i], newExample, -1)
|
|
||||||
|
newvalue = newExample
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
input = input.replace(found[i], actionlist[j].example, -1)
|
newvalue = actionlist[j].example
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log("REPLACE: ", foundlocation, fixedVariable, newvalue)
|
||||||
|
if (newvalue !== "") {
|
||||||
|
if (foundlocation === -1) {
|
||||||
|
input = input.replace(fixedVariable, newvalue, 1)
|
||||||
|
} else {
|
||||||
|
// Ensures we don't just randomly replace the first value we find
|
||||||
|
const replacedSlice = input.slice(foundlocation, input.length).replace(fixedVariable, newvalue, 1)
|
||||||
|
input = input.slice(0, foundlocation) + replacedSlice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Replace error: ", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valuefound) {
|
if (!valuefound) {
|
||||||
@@ -1334,7 +1395,7 @@ const CodeEditor = (props) => {
|
|||||||
|
|
||||||
const usedposition = e.offsetY
|
const usedposition = e.offsetY
|
||||||
if (usedposition === undefined || usedposition === null) {
|
if (usedposition === undefined || usedposition === null) {
|
||||||
toast.info("Error: LayerY is undefined or null. Please contact support@shuffler.io")
|
toast.info(`Error: LayerY is undefined or null. Please contact ${supportEmail}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1461,17 +1522,19 @@ const CodeEditor = (props) => {
|
|||||||
setActiveDialog("codeeditor")
|
setActiveDialog("codeeditor")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: {
|
sx: {
|
||||||
// zIndex: 12501,
|
// zIndex: 12501,
|
||||||
pointerEvents: "auto",
|
pointerEvents: "auto",
|
||||||
color: "white",
|
color: theme.palette.DialogStyle.color,
|
||||||
minWidth: isMobile ? "100%" : isFileEditor ? 650 : "80%",
|
minWidth: isMobile || isWorkflowEditor ? "100%" : isFileEditor ? "650px" : "80%",
|
||||||
maxWidth: isMobile ? "100%" : isFileEditor ? 650 : 1100,
|
maxWidth: isMobile || isWorkflowEditor ? "100%" : isFileEditor ? "650px" : "1100px",
|
||||||
minHeight: isMobile ? "100%" : "auto",
|
minHeight: isMobile || isWorkflowEditor ? "100%" : "auto",
|
||||||
maxHeight: isMobile ? "100%" : 700,
|
maxHeight: isMobile || isWorkflowEditor ? "100%" : "700px",
|
||||||
border: "3px solid rgba(255,255,255,0.3)",
|
border: "3px solid rgba(255,255,255,0.3)",
|
||||||
padding: isMobile ? "25px 10px 25px 10px" : 25,
|
padding: isMobile ? "25px 10px 25px 10px" : isWorkflowEditor ? "25px 10px 25px 200px" : "25px",
|
||||||
backgroundColor: "black",
|
backgroundColor: themeMode === "dark" ? "black" : theme.palette.DialogStyle.backgroundColor,
|
||||||
|
|
||||||
|
opacity: isWorkflowEditor ? 0.93 : 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -1522,7 +1585,10 @@ const CodeEditor = (props) => {
|
|||||||
color: "grey",
|
color: "grey",
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate("")
|
if (isFileEditor !== true) {
|
||||||
|
navigate("")
|
||||||
|
}
|
||||||
|
|
||||||
setExpansionModalOpen(false)
|
setExpansionModalOpen(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -1652,7 +1718,7 @@ const CodeEditor = (props) => {
|
|||||||
Code Editor
|
Code Editor
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
*/}
|
*/}
|
||||||
{isFileEditor ? null :
|
{isFileEditor || isWorkflowEditor ? null :
|
||||||
<div style={{ display: "flex", maxHeight: 40, }}>
|
<div style={{ display: "flex", maxHeight: 40, }}>
|
||||||
<ButtonGroup style={{ borderRadius: theme.palette.borderRadius, }}>
|
<ButtonGroup style={{ borderRadius: theme.palette.borderRadius, }}>
|
||||||
{userdata !== undefined && userdata !== null && userdata.support === true ?
|
{userdata !== undefined && userdata !== null && userdata.support === true ?
|
||||||
@@ -1666,6 +1732,7 @@ const CodeEditor = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
width: 175,
|
width: 175,
|
||||||
|
textWrap: 'nowrap'
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setSourceDataOpen(!sourceDataOpen)
|
setSourceDataOpen(!sourceDataOpen)
|
||||||
@@ -1685,6 +1752,7 @@ const CodeEditor = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
width: 120,
|
width: 120,
|
||||||
|
textWrap: "nowrap"
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
@@ -1720,13 +1788,14 @@ const CodeEditor = (props) => {
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
style={{
|
style={{
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
width: 120,
|
width: 145,
|
||||||
|
textWrap: "nowrap"
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setAnchorEl3(event.currentTarget);
|
setAnchorEl3(event.currentTarget);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Python Code
|
Python Examples
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
id="basic-button"
|
id="basic-button"
|
||||||
@@ -1738,6 +1807,7 @@ const CodeEditor = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
width: 130,
|
width: 130,
|
||||||
|
textWrap: "nowrap",
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setMenuPosition({
|
setMenuPosition({
|
||||||
@@ -1761,7 +1831,12 @@ const CodeEditor = (props) => {
|
|||||||
>
|
>
|
||||||
{pythonFilters.map((item, index) => {
|
{pythonFilters.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem key={index} onClick={() => {
|
<MenuItem
|
||||||
|
style={{
|
||||||
|
borderTop: item.name === "Use files" || (item.name.toLowerCase().includes("run") && item.name.toLowerCase().includes("subflow")) ? "2px solid rgba(255,255,255,0.3)" : "none",
|
||||||
|
|
||||||
|
}}
|
||||||
|
key={index} onClick={() => {
|
||||||
if (item.disabled) {
|
if (item.disabled) {
|
||||||
toast.error("This feature may not work in your environment until you update your Shuffle Tools app.", { autoClose: 10000 })
|
toast.error("This feature may not work in your environment until you update your Shuffle Tools app.", { autoClose: 10000 })
|
||||||
}
|
}
|
||||||
@@ -2114,15 +2189,15 @@ const CodeEditor = (props) => {
|
|||||||
console.log("DROP: ", e)
|
console.log("DROP: ", e)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(availableVariables !== undefined && availableVariables !== null && availableVariables.length > 0) || isFileEditor ? (
|
{(availableVariables !== undefined && availableVariables !== null && availableVariables.length > 0) || isFileEditor || isWorkflowEditor ? (
|
||||||
<AceEditor
|
<AceEditor
|
||||||
id="shuffle-codeeditor"
|
id="shuffle-codeeditor"
|
||||||
name="shuffle-codeeditor"
|
name="shuffle-codeeditor"
|
||||||
value={localcodedata}
|
value={localcodedata}
|
||||||
mode={selectedAction === undefined ? "json" : selectedAction.name === "execute_python" ? "python" : selectedAction.name === "execute_bash" ? "bash" : "json"}
|
mode={isWorkflowEditor ? "yaml" : selectedAction === undefined ? "json" : selectedAction.name === "execute_python" ? "python" : selectedAction.name === "execute_bash" ? "bash" : "json"}
|
||||||
theme="gruvbox"
|
theme="gruvbox"
|
||||||
height={isFileEditor ? 450 : 550}
|
height={isFileEditor ? 450 : isWorkflowEditor ? "90vh" : 550}
|
||||||
width={isFileEditor ? 650 : "100%"}
|
width={isFileEditor ? 650 : isWorkflowEditor ? "90vw" : "100%"}
|
||||||
|
|
||||||
markers={markers}
|
markers={markers}
|
||||||
highlightActiveLine={false}
|
highlightActiveLine={false}
|
||||||
@@ -2183,7 +2258,7 @@ const CodeEditor = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isFileEditor ? null :
|
{isFileEditor || isWorkflowEditor ? null :
|
||||||
<div style={{
|
<div style={{
|
||||||
flex: sourceDataOpen ? 1.5 : 3,
|
flex: sourceDataOpen ? 1.5 : 3,
|
||||||
marginLeft: 5,
|
marginLeft: 5,
|
||||||
@@ -2199,7 +2274,9 @@ const CodeEditor = (props) => {
|
|||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
cursor: "move"
|
cursor: "move",
|
||||||
|
color: theme.palette.DialogStyle.color,
|
||||||
|
backgroundColor: "transparent",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
@@ -2227,7 +2304,7 @@ const CodeEditor = (props) => {
|
|||||||
{
|
{
|
||||||
selectedEdge && Object.keys(selectedEdge).length > 0 ?
|
selectedEdge && Object.keys(selectedEdge).length > 0 ?
|
||||||
<ArrowForwardIcon style={{
|
<ArrowForwardIcon style={{
|
||||||
color: "rgba(255,255,255,0.7)",
|
color: theme.palette.textPrimary,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
marginLeft: -5,
|
marginLeft: -5,
|
||||||
marginRight: -5,
|
marginRight: -5,
|
||||||
@@ -2252,7 +2329,7 @@ const CodeEditor = (props) => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<span style={{ color: "white" }}>
|
<span style={{ color: theme.palette.text.primary }}>
|
||||||
{selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ?
|
{selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ?
|
||||||
"Code to run" :
|
"Code to run" :
|
||||||
triggerId ?
|
triggerId ?
|
||||||
@@ -2269,9 +2346,8 @@ const CodeEditor = (props) => {
|
|||||||
<div style={{}}>
|
<div style={{}}>
|
||||||
<Tooltip title="Try it! This runs the Shuffle Tools 'repeat back to me' or 'execute python' action with what you see in the expected output window. Commonly used to test your Python scripts or Liquid filters, not requiring the full workflow to run again." placement="top">
|
<Tooltip title="Try it! This runs the Shuffle Tools 'repeat back to me' or 'execute python' action with what you see in the expected output window. Commonly used to test your Python scripts or Liquid filters, not requiring the full workflow to run again." placement="top">
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
id="try-it-button"
|
||||||
disabled={executing}
|
disabled={executing}
|
||||||
color="primary"
|
|
||||||
style={{
|
style={{
|
||||||
border: `1px solid rgba(255, 255, 255, 0.15)`,
|
border: `1px solid rgba(255, 255, 255, 0.15)`,
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -2282,11 +2358,14 @@ const CodeEditor = (props) => {
|
|||||||
zIndex: 1200,
|
zIndex: 1200,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
backgroundColor: "rgba(33, 33, 33, 0.95)",
|
textTransform: "none",
|
||||||
|
backgroundColor: theme.palette.platformColor,
|
||||||
backdropFilter: "blur(8px)",
|
backdropFilter: "blur(8px)",
|
||||||
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08)",
|
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08)",
|
||||||
transition: "all 0.2s ease",
|
transition: "all 0.2s ease",
|
||||||
borderRadius: "4px",
|
paddingRight: 20,
|
||||||
|
color: "#FF8544",
|
||||||
|
borderRadius: theme.palette?.borderRadius,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "rgba(45, 45, 45, 0.95)",
|
backgroundColor: "rgba(45, 45, 45, 0.95)",
|
||||||
transform: "translateY(-1px)",
|
transform: "translateY(-1px)",
|
||||||
@@ -2303,7 +2382,23 @@ const CodeEditor = (props) => {
|
|||||||
{executing ?
|
{executing ?
|
||||||
<CircularProgress style={{ height: 18, width: 18, }} />
|
<CircularProgress style={{ height: 18, width: 18, }} />
|
||||||
:
|
:
|
||||||
<span>{selectedAction === undefined ? "Try it" : selectedAction.name === "execute_python" ? "Run Python Code" : selectedAction.name === "execute_bash" ? "Run Bash" : "Try it"}<PlayArrowIcon style={{ height: 18, width: 18, marginBottom: -4, marginLeft: 5, }} /> </span>
|
<span>
|
||||||
|
|
||||||
|
<PlayArrowIcon style={{ height: 18, width: 18, marginBottom: -4, marginLeft: 5, }} />
|
||||||
|
{selectedAction === undefined ? <Typography style={{color: "inherit"}}>Try it</Typography> : selectedAction.name === "execute_python" ? "Run Python Code" : selectedAction.name === "execute_bash" ? "Run Bash" : "Try it"}
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: "#C8C8C8",
|
||||||
|
fontSize: "12px",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
marginLeft: 5,
|
||||||
|
marginRight: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<kbd>Ctrl</kbd> + <kbd><KeyboardReturnIcon style={{width: 13, position: "absolute", marginLeft: 3, top: 5, }}/></kbd>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -2428,7 +2523,7 @@ const CodeEditor = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex', width: isWorkflowEditor ? "90%" : "100%", }}>
|
||||||
<Button
|
<Button
|
||||||
style={{
|
style={{
|
||||||
height: 35,
|
height: 35,
|
||||||
@@ -2451,6 +2546,7 @@ const CodeEditor = (props) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
disabled={isWorkflowEditor}
|
||||||
style={{
|
style={{
|
||||||
height: 35,
|
height: 35,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -2458,13 +2554,11 @@ const CodeEditor = (props) => {
|
|||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
/*
|
if (isWorkflowEditor === true) {
|
||||||
const clickedFieldId = "rightside_field_" + fieldCount
|
setExpansionModalOpen(false)
|
||||||
const clickedField = document.getElementById(clickedFieldId)
|
navigate("")
|
||||||
if (clickedField !== undefined && clickedField !== null) {
|
return
|
||||||
clickedField.focus()
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
if (isFileEditor !== true) {
|
if (isFileEditor !== true) {
|
||||||
navigate("")
|
navigate("")
|
||||||
@@ -2475,7 +2569,8 @@ const CodeEditor = (props) => {
|
|||||||
var fixedcodedata = localcodedata
|
var fixedcodedata = localcodedata
|
||||||
const valid = validateJson(localcodedata, true)
|
const valid = validateJson(localcodedata, true)
|
||||||
if (valid.valid) {
|
if (valid.valid) {
|
||||||
fixedcodedata = JSON.stringify(valid.result, null, 2)
|
//fixedcodedata = JSON.stringify(valid.result, null, 2)
|
||||||
|
fixedcodedata = JSON.stringify(valid.result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(codedata)
|
// console.log(codedata)
|
||||||
@@ -2491,7 +2586,7 @@ const CodeEditor = (props) => {
|
|||||||
|
|
||||||
// Handle condition fields
|
// Handle condition fields
|
||||||
if (conditionField !== null && handleConditionFieldChange !== undefined) {
|
if (conditionField !== null && handleConditionFieldChange !== undefined) {
|
||||||
handleConditionFieldChange(conditionField, fieldName, fixedcodedata);
|
handleConditionFieldChange(conditionField, fixedcodedata);
|
||||||
}
|
}
|
||||||
// Handle action fields
|
// Handle action fields
|
||||||
else if (actionId !== undefined && actionId !== null && actionId.length > 0) {
|
else if (actionId !== undefined && actionId !== null && actionId.length > 0) {
|
||||||
@@ -2499,7 +2594,7 @@ const CodeEditor = (props) => {
|
|||||||
}
|
}
|
||||||
// Handle trigger fields
|
// Handle trigger fields
|
||||||
else if (triggerId !== undefined && triggerId !== null && triggerId.length > 0) {
|
else if (triggerId !== undefined && triggerId !== null && triggerId.length > 0) {
|
||||||
handleSubflowParamChange(triggerId, triggerField, fixedcodedata)
|
handleTriggerParamChange(triggerId, triggerField, fixedcodedata)
|
||||||
}
|
}
|
||||||
|
|
||||||
setExpansionModalOpen(false)
|
setExpansionModalOpen(false)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useContext, memo } from "react";
|
import React, { useState, useEffect, useContext, memo } from "react";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import {
|
import {
|
||||||
FormControl,
|
FormControl,
|
||||||
InputLabel,
|
InputLabel,
|
||||||
@@ -35,7 +35,7 @@ import {
|
|||||||
import ModeEditOutlineOutlinedIcon from '@mui/icons-material/ModeEditOutlineOutlined';
|
import ModeEditOutlineOutlinedIcon from '@mui/icons-material/ModeEditOutlineOutlined';
|
||||||
import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined';
|
import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined';
|
||||||
|
|
||||||
import theme from "../theme.jsx";
|
import {getTheme} from "../theme.jsx";
|
||||||
const ITEM_HEIGHT = 48;
|
const ITEM_HEIGHT = 48;
|
||||||
const ITEM_PADDING_TOP = 8;
|
const ITEM_PADDING_TOP = 8;
|
||||||
const MenuProps = {
|
const MenuProps = {
|
||||||
@@ -75,12 +75,16 @@ const UserManagmentTab = memo((props) => {
|
|||||||
const [logsViewModal, setLogsViewModal] = React.useState(false);
|
const [logsViewModal, setLogsViewModal] = React.useState(false);
|
||||||
const [ipSelected, setIpSelected] = React.useState("");
|
const [ipSelected, setIpSelected] = React.useState("");
|
||||||
const [userLogViewing, setUserLogViewing] = React.useState({});
|
const [userLogViewing, setUserLogViewing] = React.useState({});
|
||||||
|
const { themeMode, supportEmail, brandColor } = useContext(Context);
|
||||||
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedOrganization?.mfa_required !== MFARequired) {
|
if (selectedOrganization?.mfa_required !== MFARequired) {
|
||||||
setMFARequired(selectedOrganization?.mfa_required);
|
setMFARequired(selectedOrganization?.mfa_required);
|
||||||
}
|
}
|
||||||
}, [selectedOrganization]);
|
}, [selectedOrganization]);
|
||||||
|
|
||||||
useEffect(() => { if(users?.length === 0){
|
useEffect(() => { if(users?.length === 0){
|
||||||
getUsers();
|
getUsers();
|
||||||
} }, []);
|
} }, []);
|
||||||
@@ -248,6 +252,14 @@ const UserManagmentTab = memo((props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.target.value.includes("ALL")) {
|
||||||
|
toast.info("Adding to available all sub-organizations. This may take a minute.")
|
||||||
|
event.target.value = selectedOrganization.child_orgs.map((org) => org.id)
|
||||||
|
} else if (event.target.value.includes("None")) {
|
||||||
|
toast.info("Removing from all sub-organizations. This may take a minute")
|
||||||
|
event.target.value = []
|
||||||
|
}
|
||||||
|
|
||||||
console.log("event: ", event.target.value);
|
console.log("event: ", event.target.value);
|
||||||
setMatchingOrganizations(event.target.value);
|
setMatchingOrganizations(event.target.value);
|
||||||
// Workaround for empty orgs
|
// Workaround for empty orgs
|
||||||
@@ -286,6 +298,14 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
MenuProps={MenuProps}
|
MenuProps={MenuProps}
|
||||||
>
|
>
|
||||||
|
<MenuItem key={-2} value={"None"}>
|
||||||
|
<Checkbox checked={false} />
|
||||||
|
<ListItemText primary={"None"} />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key={-1} value={"ALL"}>
|
||||||
|
<Checkbox checked={false} />
|
||||||
|
<ListItemText primary={"ALL"} />
|
||||||
|
</MenuItem>
|
||||||
{selectedOrganization.child_orgs.map((org, index) => (
|
{selectedOrganization.child_orgs.map((org, index) => (
|
||||||
<MenuItem key={index} value={org.id}>
|
<MenuItem key={index} value={org.id}>
|
||||||
<Checkbox checked={matchingOrganizations.indexOf(org.id) > -1} />
|
<Checkbox checked={matchingOrganizations.indexOf(org.id) > -1} />
|
||||||
@@ -347,7 +367,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
toast("Failed to deactivate user: " + responseJson.reason);
|
toast("Failed to deactivate user: " + responseJson.reason);
|
||||||
} else if (responseJson.success === false) {
|
} else if (responseJson.success === false) {
|
||||||
toast(
|
toast(
|
||||||
"Failed to deactivate user. Please contact support@shuffler.io if this persists.",
|
`Failed to deactivate user. Please contact ${supportEmail} if this persists.`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
toast("Changed activation for user " + data.id);
|
toast("Changed activation for user " + data.id);
|
||||||
@@ -586,7 +606,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<Typography style={{ color: "white", textTransform: 'none', fontSize: 24 }}>
|
<Typography variant="h5" style={{ textTransform: 'none', fontSize: 24 }}>
|
||||||
Add user
|
Add user
|
||||||
</Typography>
|
</Typography>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
@@ -603,7 +623,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: "50px",
|
height: "50px",
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -636,7 +656,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: "50px",
|
height: "50px",
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -666,17 +686,17 @@ const UserManagmentTab = memo((props) => {
|
|||||||
</div>
|
</div>
|
||||||
{loginInfo}
|
{loginInfo}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', p: 2, backgroundColor: "#212121" }}>
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', p: 2, backgroundColor: theme.palette.platformColor }}>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#ff8544", marginRight: 5 }}
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, marginRight: 5, color: theme.palette.primary.main }}
|
||||||
onClick={() => setModalOpen(false)}
|
onClick={() => setModalOpen(false)}
|
||||||
color="primary"
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#1a1a1a", backgroundColor: "#ff8544" }}
|
color="primary"
|
||||||
|
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16,}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isCloud) {
|
if (isCloud) {
|
||||||
inviteUser(modalUser);
|
inviteUser(modalUser);
|
||||||
@@ -684,7 +704,6 @@ const UserManagmentTab = memo((props) => {
|
|||||||
submitUser(modalUser);
|
submitUser(modalUser);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
color="primary"
|
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
@@ -735,7 +754,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle style={{ maxWidth: "800px", width: "100%", textAlign: "center", margin: "auto", backgroundColor: theme?.palette?.DialogStyle?.backgroundColor}}>
|
<DialogTitle style={{ maxWidth: "800px", width: "100%", textAlign: "center", margin: "auto", backgroundColor: theme?.palette?.DialogStyle?.backgroundColor}}>
|
||||||
<span style={{ color: "white", backgroundColor: theme?.palette?.DialogStyle?.backgroundColor }}>
|
<span style={{ color: theme.palette.text.primary, backgroundColor: theme?.palette?.DialogStyle?.backgroundColor }}>
|
||||||
<EditIcon style={{ marginTop: 5 }} /> Editing {selectedUser.username}
|
<EditIcon style={{ marginTop: 5 }} /> Editing {selectedUser.username}
|
||||||
</span>
|
</span>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
@@ -752,7 +771,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 50,
|
height: 50,
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -795,7 +814,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 50,
|
height: 50,
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -829,9 +848,10 @@ const UserManagmentTab = memo((props) => {
|
|||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div style={{ margin: "auto", maxWidth: 450 }}>
|
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', margin: "auto", maxWidth: 450 }}>
|
||||||
<Button
|
<div style={{ display: "flex", justifyContent: "space-between", width: "100%" }}>
|
||||||
style={{textTransform: 'none', fontSize: 16}}
|
<Button
|
||||||
|
style={{textTransform: 'none', fontSize: 16, whiteSpace: 'nowrap', textWrap: 'nowarp'}}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={selectedUser.username === userdata.username}
|
disabled={selectedUser.username === userdata.username}
|
||||||
@@ -843,7 +863,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
{selectedUser.active ? "Delete from org" : "Delete from org"}
|
{selectedUser.active ? "Delete from org" : "Delete from org"}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
style={{ textTransform: 'none', fontSize: 16 }}
|
style={{ textTransform: 'none', fontSize: 16, whiteSpace: 'nowrap', textWrap: 'nowarp', }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={
|
disabled={
|
||||||
@@ -864,7 +884,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}
|
}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{textTransform: 'none', fontSize: 16}}
|
style={{textTransform: 'none', fontSize: 16, whiteSpace: 'nowrap', textWrap: 'nowarp', }}
|
||||||
>
|
>
|
||||||
{selectedUser.mfa_info !== undefined &&
|
{selectedUser.mfa_info !== undefined &&
|
||||||
selectedUser.mfa_info !== null &&
|
selectedUser.mfa_info !== null &&
|
||||||
@@ -872,6 +892,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
? "Disable 2FA"
|
? "Disable 2FA"
|
||||||
: "Enable 2FA"}
|
: "Enable 2FA"}
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{isCloud && userdata.support && selectedUser.id !== userdata.id ? (
|
{isCloud && userdata.support && selectedUser.id !== userdata.id ? (
|
||||||
<Button
|
<Button
|
||||||
@@ -881,6 +902,8 @@ const UserManagmentTab = memo((props) => {
|
|||||||
marginTop: 50,
|
marginTop: 50,
|
||||||
border: "1px solid #d52b2b",
|
border: "1px solid #d52b2b",
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textWrap: 'nowarp',
|
||||||
color:
|
color:
|
||||||
showDeleteAccountTextbox === true &&
|
showDeleteAccountTextbox === true &&
|
||||||
deleteAccountText?.length > 0 &&
|
deleteAccountText?.length > 0 &&
|
||||||
@@ -932,7 +955,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 50,
|
height: 50,
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -1003,7 +1026,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 50,
|
height: 50,
|
||||||
color: "white",
|
color: theme.palette.textFieldStyle.color,
|
||||||
fontSize: "1em",
|
fontSize: "1em",
|
||||||
},
|
},
|
||||||
maxLength: 6,
|
maxLength: 6,
|
||||||
@@ -1111,7 +1134,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<span style={{ color: "white" }}>User Logs</span>
|
<span style={{ color: theme.palette.text.primary }}>User Logs</span>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
{/* ask user for which IP they want to see logs for by iterating of user.login_info */}
|
{/* ask user for which IP they want to see logs for by iterating of user.login_info */}
|
||||||
@@ -1253,23 +1276,23 @@ const UserManagmentTab = memo((props) => {
|
|||||||
) : null
|
) : null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: '#212121',borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", }}>
|
<div style={{ width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor, borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", }}>
|
||||||
{modalView}
|
{modalView}
|
||||||
{editUserModal}
|
{editUserModal}
|
||||||
{logview}
|
{logview}
|
||||||
<div style={{ height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
|
<div style={{ height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
|
||||||
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin' }}>
|
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin' }}>
|
||||||
<div style={{display: 'flex', justifyContent: 'space-between'}}>
|
<div style={{display: 'flex', justifyContent: 'space-between'}}>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ marginBottom: 20 }}>
|
<div style={{ marginBottom: 20 }}>
|
||||||
<h2 style={{ marginBottom: 8, marginTop: 0, color: "#FFFFFF" }}>User Management</h2>
|
<Typography variant="h5" style={{ marginBottom: 8, marginTop: 0, }}>User Management</Typography>
|
||||||
<span style={{ color: "#9E9E9E" }}>
|
<Typography variant="body2" color="textSecondary">
|
||||||
Add, edit, distribute or remove users from your organization.{" "}
|
Add, edit, distribute or remove users from your organization.{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/admin?admin_tab=sso"
|
href="/admin?admin_tab=sso"
|
||||||
style={{ color: "#FF8444" }}
|
style={{ color: theme.palette.linkColor }}
|
||||||
>
|
>
|
||||||
Configure SSO
|
Configure SSO
|
||||||
</a>
|
</a>
|
||||||
@@ -1280,15 +1303,15 @@ const UserManagmentTab = memo((props) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="/docs/organizations#user_management"
|
href="/docs/organizations#user_management"
|
||||||
style={{ color: "#FF8444" }}
|
style={{ color: theme.palette.linkColor }}
|
||||||
>
|
>
|
||||||
learn more about users
|
learn more about users
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div />
|
<div />
|
||||||
<Button
|
<Button
|
||||||
style={{ color: "#1a1a1a", backgroundColor: "#ff8544",fontSize: 16, textTransform: 'none', borderRadius: 4, width: 162, height: 40, boxShadow: 'none' }}
|
style={{ fontSize: 16, textTransform: 'none', borderRadius: 4, width: 162, height: 40, boxShadow: 'none' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => setModalOpen(true)}
|
onClick={() => setModalOpen(true)}
|
||||||
@@ -1296,9 +1319,9 @@ const UserManagmentTab = memo((props) => {
|
|||||||
Add user
|
Add user
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
style={{ backgroundColor: "#2F2F2F", boxShadow: 'none', borderRadius: 4, width: 81, height: 40, marginLeft: 16, marginRight: 15 }}
|
style={{ boxShadow: 'none', borderRadius: 4, width: 81, height: 40, marginLeft: 16, marginRight: 15 }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="secondary"
|
||||||
onClick={() => getUsers()}
|
onClick={() => getUsers()}
|
||||||
>
|
>
|
||||||
<CachedIcon />
|
<CachedIcon />
|
||||||
@@ -1318,7 +1341,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
border: "1px solid #494949",
|
border: theme.palette.defaultBorder,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
@@ -1334,8 +1357,8 @@ const UserManagmentTab = memo((props) => {
|
|||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItem style={{ width: "100%", padding: "10px 10px 10px 0px", verticalAlign: 'middle', borderBottom: "1px solid #494949", display: "table-row" }}>
|
<ListItem style={{ width: "100%", padding: "10px 10px 10px 0px", verticalAlign: 'middle', borderBottom: theme.palette.defaultBorder, display: "table-row" }}>
|
||||||
{["Username", /*"API Key",*/ "Role", /*"Active",*/ "Type", "MFA", ...(selectedOrganization?.child_orgs?.length > 0 ? ["Suborgs"]: []), "Actions", "Last Login"].map((header, index) => (
|
{[...(isCloud ? ["Region"] : []), "Username", /*"API Key",*/ "Role", /*"Active",*/ "Type", "MFA", ...(selectedOrganization?.child_orgs?.length > 0 ? ["Suborgs"]: []), "Actions", "Last Login"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
key={index}
|
key={index}
|
||||||
primary={header}
|
primary={header}
|
||||||
@@ -1344,7 +1367,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
borderBottom: "1px solid #494949",
|
borderBottom: theme.palette.defaultBorder,
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
verticalAlign: "middle",
|
verticalAlign: "middle",
|
||||||
}}
|
}}
|
||||||
@@ -1357,10 +1380,10 @@ const UserManagmentTab = memo((props) => {
|
|||||||
key={rowIndex}
|
key={rowIndex}
|
||||||
style={{
|
style={{
|
||||||
display: "table-row",
|
display: "table-row",
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(9)
|
{Array(isCloud ? 7 : 6)
|
||||||
.fill()
|
.fill()
|
||||||
.map((_, colIndex) => (
|
.map((_, colIndex) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
@@ -1374,7 +1397,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
variant="text"
|
variant="text"
|
||||||
animation="wave"
|
animation="wave"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1a1a1a",
|
backgroundColor: theme.palette.loaderColor,
|
||||||
height: "20px",
|
height: "20px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
@@ -1385,9 +1408,9 @@ const UserManagmentTab = memo((props) => {
|
|||||||
))
|
))
|
||||||
): users === 0 ? null
|
): users === 0 ? null
|
||||||
: users?.map((data, index) => {
|
: users?.map((data, index) => {
|
||||||
var bgColor = "#212121";
|
var bgColor = themeMode === "dark" ? "#212121" : "#FFFFFF";
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
bgColor = "#1A1A1A";
|
bgColor = themeMode === "dark" ? "#1A1A1A" : "#EAEAEA";
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeNow = new Date().getTime();
|
const timeNow = new Date().getTime();
|
||||||
@@ -1418,8 +1441,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
style={{
|
style={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
textDecoration: "underline",
|
textDecoration: "underline",
|
||||||
textDecorationColor: "#F76742",
|
color: theme.palette.linkColor,
|
||||||
color: "#F76742",
|
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setLogsViewModal(true);
|
setLogsViewModal(true);
|
||||||
@@ -1436,8 +1458,16 @@ const UserManagmentTab = memo((props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const userRegion = data?.user_geo_info?.country?.iso_code
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem key={index} style={{ backgroundColor: bgColor, display: 'table-row', borderBottomLeftRadius: users?.length - 1 === index ? 8 : 0, borderBottomRightRadius: users?.length - 1 === index ? 8 : 0 }}>
|
<ListItem key={index} style={{ backgroundColor: bgColor, display: 'table-row', borderBottomLeftRadius: users?.length - 1 === index ? 8 : 0, borderBottomRightRadius: users?.length - 1 === index ? 8 : 0 }}>
|
||||||
|
{isCloud ? (
|
||||||
|
<ListItemText
|
||||||
|
primary={(<img src={`https://flagcdn.com/48x36/${userRegion.toLowerCase()}.png`} alt={data?.user_geo_info?.country?.iso_code} style={{ marginRight: 30, width: 25, height: 23, }} />)}
|
||||||
|
style={{ display: 'table-cell', verticalAlign: 'middle', textAlign: 'center' }}
|
||||||
|
/>) : null}
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={(
|
primary={(
|
||||||
<Tooltip title={data.username || 'No username available'}>
|
<Tooltip title={data.username || 'No username available'}>
|
||||||
@@ -1449,7 +1479,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
maxWidth: 150,
|
maxWidth: 150,
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
width: 'auto',
|
width: 'auto',
|
||||||
color: "#FF8444",
|
color: theme.palette.primary.main,
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
@@ -1506,8 +1536,8 @@ const UserManagmentTab = memo((props) => {
|
|||||||
setUser(data.id, "role", e.target.value);
|
setUser(data.id, "role", e.target.value);
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#1A1A1A",
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
height: "50px",
|
height: "50px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
marginTop: "8px",
|
marginTop: "8px",
|
||||||
@@ -1526,27 +1556,35 @@ const UserManagmentTab = memo((props) => {
|
|||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
value={"admin"}
|
value={"admin"}
|
||||||
>
|
>
|
||||||
Org Admin
|
Org Admin
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={{
|
sx={{
|
||||||
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
value={"user"}
|
value={"user"}
|
||||||
>
|
>
|
||||||
Org User
|
Org User
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={{
|
sx={{
|
||||||
backgroundColor: theme.palette.textFieldStyle.backgroundColor,
|
backgroundColor: theme.palette.backgroundColor,
|
||||||
color: "white",
|
color: theme.palette.textColor,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.hoverColor,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
value={"org-reader"}
|
value={"org-reader"}
|
||||||
>
|
>
|
||||||
@@ -1557,10 +1595,12 @@ const UserManagmentTab = memo((props) => {
|
|||||||
style={{ display:'table-cell', verticalAlign: 'middle' }}
|
style={{ display:'table-cell', verticalAlign: 'middle' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/*
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={data.active ? "True" : "False"}
|
primary={data.active ? "True" : "False"}
|
||||||
style={{display:'table-cell',verticalAlign: 'middle' , padding: "8px", textAlign: "center", color: data.active ? "#02CB70" : "#F53434" }}
|
style={{display:'table-cell',verticalAlign: 'middle' , padding: "8px", textAlign: "center", color: data.active ? "#02CB70" : "#F53434" }}
|
||||||
/>
|
/>
|
||||||
|
*/}
|
||||||
|
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
@@ -1573,7 +1613,6 @@ const UserManagmentTab = memo((props) => {
|
|||||||
style={{ display:'table-cell',verticalAlign: 'middle', padding: "8px", }}
|
style={{ display:'table-cell',verticalAlign: 'middle', padding: "8px", }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*
|
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
data?.mfa_info !== undefined &&
|
data?.mfa_info !== undefined &&
|
||||||
@@ -1584,7 +1623,6 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}
|
}
|
||||||
style={{ display:'table-cell', verticalAlign: 'middle',padding: "8px", color: data.mfa_info.active ? "#02CB70" : "#F53434" }}
|
style={{ display:'table-cell', verticalAlign: 'middle',padding: "8px", color: data.mfa_info.active ? "#02CB70" : "#F53434" }}
|
||||||
/>
|
/>
|
||||||
*/}
|
|
||||||
|
|
||||||
{selectedOrganization?.child_orgs !== undefined &&
|
{selectedOrganization?.child_orgs !== undefined &&
|
||||||
selectedOrganization?.child_orgs !== null &&
|
selectedOrganization?.child_orgs !== null &&
|
||||||
@@ -1648,7 +1686,20 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img src="/icons/editIcon.svg" alt="edit icon" style={{width: 24, height: 24}} />
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.1038 4.66848C16.3158 4.45654 16.5674 4.28843 16.8443 4.17373C17.1212 4.05903 17.418 4 17.7177 4C18.0174 4 18.3142 4.05903 18.5911 4.17373C18.868 4.28843 19.1196 4.45654 19.3315 4.66848C19.5435 4.88041 19.7116 5.13201 19.8263 5.40891C19.941 5.68582 20 5.9826 20 6.28232C20 6.58204 19.941 6.87882 19.8263 7.15573C19.7116 7.43263 19.5435 7.68423 19.3315 7.89617L8.43807 18.7896L4 20L5.21038 15.5619L16.1038 4.66848Z"
|
||||||
|
stroke={themeMode=== "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{/* <Button
|
{/* <Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||