commit
56f4e8eae2
2
.github/config.json
vendored
2
.github/config.json
vendored
File diff suppressed because one or more lines are too long
14
.github/workflows/fat-migration.yml
vendored
14
.github/workflows/fat-migration.yml
vendored
|
|
@ -218,11 +218,12 @@ jobs:
|
|||
run: echo "I'm alive!" && exit 0
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
# Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again
|
||||
- name: Cache maven dependencies
|
||||
|
|
@ -485,11 +486,12 @@ jobs:
|
|||
run: echo ${{ steps.run_result.outputs.run_result }}
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Download the react build artifact
|
||||
uses: actions/download-artifact@v2
|
||||
|
|
|
|||
6
.github/workflows/github-release.yml
vendored
6
.github/workflows/github-release.yml
vendored
|
|
@ -114,11 +114,11 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: adopt
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
# Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again
|
||||
- name: Cache maven dependencies
|
||||
|
|
|
|||
14
.github/workflows/integration-tests-command.yml
vendored
14
.github/workflows/integration-tests-command.yml
vendored
|
|
@ -151,12 +151,12 @@ jobs:
|
|||
run: echo ${{ steps.run_result.outputs.run_result }}
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: adopt
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Download the client build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
|
|
@ -226,6 +226,7 @@ jobs:
|
|||
-v "$PWD/stacks:/appsmith-stacks" -e APPSMITH_LICENSE_KEY=$APPSMITH_LICENSE_KEY \
|
||||
-e APPSMITH_AUDITLOG_ENABLED=true \
|
||||
-e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \
|
||||
--add-host=host.docker.internal:host-gateway \
|
||||
fatcontainer
|
||||
|
||||
- name: Use Node.js 16.14.0
|
||||
|
|
@ -585,6 +586,13 @@ jobs:
|
|||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Download the react build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/download-artifact@v3
|
||||
|
|
|
|||
2
.github/workflows/label-checker.yml
vendored
2
.github/workflows/label-checker.yml
vendored
|
|
@ -19,5 +19,5 @@ jobs:
|
|||
- uses: docker://agilepathway/pull-request-label-checker:latest
|
||||
with:
|
||||
# Needs to have a Test Plan Approved label if not part of any of the pods below
|
||||
any_of: Test Plan Approved,App Viewers Pod,User Education Pod,New Developers Pod,Team Managers Pod,UI Builders Pod,Performance,Release Promotion,CI,Design System Pod,DevOps Pod,skip-testPlan
|
||||
any_of: Test Plan Approved,User Education Pod,DevOps Pod,Performance,CI,Release Promotion,skip-testPlan
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
8
.github/workflows/perf-test.yml
vendored
8
.github/workflows/perf-test.yml
vendored
|
|
@ -121,6 +121,14 @@ jobs:
|
|||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Download the react build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/download-artifact@v3
|
||||
|
|
|
|||
7
.github/workflows/server-build.yml
vendored
7
.github/workflows/server-build.yml
vendored
|
|
@ -85,12 +85,12 @@ jobs:
|
|||
run: echo "I'm alive!" && exit 0
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: adopt
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
# Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again
|
||||
- name: Cache maven dependencies
|
||||
|
|
@ -125,6 +125,7 @@ jobs:
|
|||
- name: Build and test
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
env:
|
||||
ACTIVE_PROFILE: test
|
||||
APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools"
|
||||
APPSMITH_CLOUD_SERVICES_BASE_URL: "https://release-cs.appsmith.com"
|
||||
APPSMITH_REDIS_URL: "redis://127.0.0.1:6379"
|
||||
|
|
|
|||
251
.github/workflows/test-build-docker-image.yml
vendored
251
.github/workflows/test-build-docker-image.yml
vendored
|
|
@ -227,12 +227,12 @@ jobs:
|
|||
run: echo "I'm alive!" && exit 0
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: adopt
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
# Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again
|
||||
- name: Cache maven dependencies
|
||||
|
|
@ -399,15 +399,235 @@ jobs:
|
|||
- name: Save the status of the run
|
||||
run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result
|
||||
|
||||
|
||||
perf-test:
|
||||
needs: [buildClient, buildServer, buildRts]
|
||||
|
||||
# Only run if the build step is successful
|
||||
if: success()
|
||||
name: perf-test
|
||||
uses: ./.github/workflows/perf-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.client_payload.pull_request.number }}
|
||||
runs-on: ubuntu-latest-4-cores
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
shell: bash
|
||||
|
||||
# Service containers to run with this job. Required for running tests
|
||||
services:
|
||||
# Label used to access the service container
|
||||
redis:
|
||||
# Docker Hub image for Redis
|
||||
image: redis
|
||||
ports:
|
||||
# Opens tcp port 6379 on the host and service container
|
||||
- 6379:6379
|
||||
mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 27017:27017
|
||||
steps:
|
||||
- name: Checkout the merged commit from PR and base branch
|
||||
if: github.event_name == 'pull_request_review'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- name: Checkout the head commit of the branch
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Timestamp will be used to create cache key
|
||||
- id: timestamp
|
||||
run: echo "timestamp=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_OUTPUT
|
||||
|
||||
# In case this is second attempt try restoring status of the prior attempt from cache
|
||||
- name: Restore the previous run result
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/run_result
|
||||
key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}
|
||||
restore-keys: |
|
||||
${{ github.run_id }}-${{ github.job }}-
|
||||
# Fetch prior run result
|
||||
- name: Get the previous run result
|
||||
id: run_result
|
||||
run: cat ~/run_result 2>/dev/null || echo 'default'
|
||||
|
||||
# In case of prior failure run the job
|
||||
- if: steps.run_result.outputs.run_result != 'success'
|
||||
run: echo "I'm alive!" && exit 0
|
||||
|
||||
# Set status = success
|
||||
- name: Save the status of the run
|
||||
run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result
|
||||
|
||||
- name: Use Node.js 16.14.0
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16.14.0"
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
id: yarn-dep-cache-dir-path
|
||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
# Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again
|
||||
- name: Cache npm dependencies
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
id: yarn-dep-cache
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-yarn-dependencies
|
||||
with:
|
||||
path: |
|
||||
${{ steps.yarn-dep-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-dep-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-dep-
|
||||
# Install all the dependencies
|
||||
- name: Install dependencies
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Download the react build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: client-build
|
||||
path: app/client/build
|
||||
|
||||
- name: Download the server build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: server-build
|
||||
path: app/server/dist
|
||||
|
||||
# Start server
|
||||
- name: start server
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: app/server
|
||||
env:
|
||||
APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools"
|
||||
APPSMITH_REDIS_URL: "redis://127.0.0.1:6379"
|
||||
APPSMITH_ENCRYPTION_PASSWORD: "password"
|
||||
APPSMITH_ENCRYPTION_SALT: "salt"
|
||||
APPSMITH_IS_SELF_HOSTED: false
|
||||
APPSMITH_CLOUD_SERVICES_BASE_URL: https://release-cs.appsmith.com
|
||||
APPSMITH_CLOUD_SERVICES_USERNAME: ""
|
||||
APPSMITH_CLOUD_SERVICES_PASSWORD: ""
|
||||
APPSMITH_GIT_ROOT: "./container-volumes/git-storage"
|
||||
APPSMITH_AUDITLOG_ENABLED: true
|
||||
run: |
|
||||
ls -l
|
||||
ls -l scripts/
|
||||
ls -l dist/
|
||||
# Run the server in the background and redirect logs to a log file
|
||||
./scripts/start-dev-server.sh &> server-logs.log &
|
||||
- name: Wait for 30 seconds for server to start
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: |
|
||||
sleep 30s
|
||||
- name: Installing Yarn serve
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: |
|
||||
yarn global add serve
|
||||
echo "$(yarn global bin)" >> $GITHUB_PATH
|
||||
# Start rts
|
||||
- name: Start RTS Server
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: ./app/rts
|
||||
run: |
|
||||
cp .env.example .env
|
||||
./start-server.sh &
|
||||
- name: Setting up the perf tests
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
shell: bash
|
||||
env:
|
||||
APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
|
||||
APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
|
||||
CYPRESS_URL: ${{ secrets.CYPRESS_URL }}
|
||||
CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
|
||||
CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
|
||||
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
|
||||
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
|
||||
CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }}
|
||||
CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }}
|
||||
CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }}
|
||||
CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }}
|
||||
CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }}
|
||||
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }}
|
||||
APPSMITH_DISABLE_TELEMETRY: true
|
||||
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
|
||||
POSTGRES_PASSWORD: postgres
|
||||
run: |
|
||||
./cypress/setup-test.sh
|
||||
- name: Checkout Performance Infra code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: appsmithorg/performance-infra
|
||||
token: ${{ secrets.APPSMITH_PERF_INFRA_REPO_PAT }}
|
||||
ref: main
|
||||
path: app/client/perf
|
||||
|
||||
- name: Installing performance tests dependencies
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: app/client/perf
|
||||
shell: bash
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Change test script permissions
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: app/client/perf
|
||||
run: chmod +x ./start-test.sh
|
||||
|
||||
- name: Run performance tests
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: app/client/perf
|
||||
shell: bash
|
||||
env:
|
||||
APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
|
||||
APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
|
||||
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME9 }}
|
||||
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD9 }}
|
||||
APPSMITH_PERFORMANCE_DB_CONFIG: ${{ secrets.APPSMITH_PERFORMANCE_DB_CONFIG }}
|
||||
APPSMITH_PERFORMANCE_S3_KEY: ${{secrets.APPSMITH_PERFORMANCE_S3_KEY}}
|
||||
APPSMITH_PERFORMANCE_S3_SECRET: ${{secrets.APPSMITH_PERFORMANCE_S3_SECRET}}
|
||||
APPSMITH_PERFORMANCE_DB_PASSWORD: ${{secrets.APPSMITH_PERFORMANCE_DB_PASSWORD}}
|
||||
APPSMITH_PERFORMANCE_DB_HOST: ${{secrets.APPSMITH_PERFORMANCE_DB_HOST}}
|
||||
PERF_GITHUB_PAT: ${{ secrets.APPSMITH_PERF_INFRA_REPO_PAT }}
|
||||
APPSMITH_DISABLE_TELEMETRY: true
|
||||
POSTGRES_PASSWORD: postgres
|
||||
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
||||
MACHINE: ubuntu-latest-4-cores
|
||||
|
||||
run: ./start-test.sh
|
||||
|
||||
# Restore the previous built bundle if present. If not push the newly built into the cache
|
||||
- name: Restore the previous bundle
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
app/client/perf/traces
|
||||
key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}
|
||||
restore-keys: |
|
||||
${{ github.run_id }}-${{ github.job }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: performance-summaries
|
||||
path: app/client/perf/traces
|
||||
|
||||
# Set status = success
|
||||
- name: Save the status of the run
|
||||
run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result
|
||||
|
||||
|
||||
fat-container-test:
|
||||
needs: [buildClient, buildServer, buildRts]
|
||||
|
|
@ -514,12 +734,12 @@ jobs:
|
|||
run: echo ${{ steps.run_result.outputs.run_result }}
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: adopt
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Download the react build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
|
|
@ -587,8 +807,9 @@ jobs:
|
|||
cd fatcontainerlocal
|
||||
docker run -d --name appsmith -p 80:80 -p 9001:9001 \
|
||||
-v "$PWD/stacks:/appsmith-stacks" -e APPSMITH_LICENSE_KEY=$APPSMITH_LICENSE_KEY \
|
||||
-e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \
|
||||
-e APPSMITH_AUDITLOG_ENABLED=true \
|
||||
-e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \
|
||||
--add-host=host.docker.internal:host-gateway \
|
||||
fatcontainer
|
||||
|
||||
- name: Use Node.js 16.14.0
|
||||
|
|
@ -945,12 +1166,12 @@ jobs:
|
|||
run: echo ${{ steps.run_result.outputs.run_result }}
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK 1.11
|
||||
- name: Set up JDK 17
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "11.0.10"
|
||||
distribution: adopt
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Download the server build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
|
|
|
|||
11
Dockerfile
11
Dockerfile
|
|
@ -13,9 +13,12 @@ ENV LC_ALL C.UTF-8
|
|||
RUN apt-get update \
|
||||
&& apt-get upgrade --yes \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --yes \
|
||||
supervisor curl cron certbot nginx gnupg netcat openssh-client \
|
||||
software-properties-common gettext openjdk-11-jdk \
|
||||
supervisor curl cron certbot nginx gnupg wget netcat openssh-client \
|
||||
software-properties-common gettext \
|
||||
python3-pip python-setuptools git ca-certificates-java \
|
||||
&& wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | apt-key add - \
|
||||
&& echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list \
|
||||
&& apt-get update && apt-get install --no-install-recommends --yes temurin-17-jdk \
|
||||
&& pip install --no-cache-dir git+https://github.com/coderanger/supervisor-stdout@973ba19967cdaf46d9c1634d1675fc65b9574f6e \
|
||||
&& apt-get remove --yes git python3-pip
|
||||
|
||||
|
|
@ -67,7 +70,7 @@ COPY ./deploy/docker/templates/nginx/* \
|
|||
templates/
|
||||
|
||||
# Add bootstrapfile
|
||||
COPY ./deploy/docker/entrypoint.sh ./deploy/docker/scripts/* ./scripts/start-backend.sh ./
|
||||
COPY ./deploy/docker/entrypoint.sh ./deploy/docker/scripts/* ./
|
||||
|
||||
# Add util tools
|
||||
COPY ./deploy/docker/utils ./utils
|
||||
|
|
@ -81,7 +84,7 @@ COPY ./deploy/docker/templates/supervisord/ templates/supervisord/
|
|||
COPY ./deploy/docker/templates/cron.d /etc/cron.d/
|
||||
RUN chmod 0644 /etc/cron.d/*
|
||||
|
||||
RUN chmod +x entrypoint.sh renew-certificate.sh healthcheck.sh start-backend.sh
|
||||
RUN chmod +x entrypoint.sh renew-certificate.sh healthcheck.sh
|
||||
|
||||
# Disable setuid/setgid bits for the files inside container.
|
||||
RUN find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true
|
||||
|
|
|
|||
34
README.md
34
README.md
|
|
@ -180,54 +180,55 @@ Lets build great software together.
|
|||
[](https://github.com/nayan-rafiq)
|
||||
[](https://github.com/jsartisan)
|
||||
[](https://github.com/yaldram)
|
||||
[](https://github.com/Rishabh-Rathod)
|
||||
[](https://github.com/aswathkk)
|
||||
[](https://github.com/ankitakinger)
|
||||
[](https://github.com/Rishabh-Rathod)
|
||||
[](https://github.com/sbalaji1192)
|
||||
[](https://github.com/ohansFavour)
|
||||
[](https://github.com/Aishwarya-U-R)
|
||||
[](https://github.com/Irongade)
|
||||
[](https://github.com/SatishGandham)
|
||||
[](https://github.com/prsidhu)
|
||||
[](https://github.com/pranavkanade)
|
||||
[](https://github.com/SatishGandham)
|
||||
[](https://github.com/yatinappsmith)
|
||||
[](https://github.com/somangshu)
|
||||
[](https://github.com/ApekshaBhosale)
|
||||
[](https://github.com/yatinappsmith)
|
||||
[](https://github.com/sidhantgoel)
|
||||
[](https://github.com/rahulramesha)
|
||||
[](https://github.com/IAmAnubhavSaini)
|
||||
[](https://github.com/Parthvi12)
|
||||
[](https://github.com/marks0351)
|
||||
[](https://github.com/albinAppsmith)
|
||||
[](https://github.com/ayushpahwa)
|
||||
[](https://github.com/AmanAgarwal041)
|
||||
[](https://github.com/ayushpahwa)
|
||||
[](https://github.com/ashit-rath)
|
||||
[](https://github.com/areyabhishek)
|
||||
[](https://github.com/ankurrsinghal)
|
||||
[](https://github.com/rimildeyjsr)
|
||||
[](https://github.com/vishnu-gp)
|
||||
[](https://github.com/cokoghenun)
|
||||
[](https://github.com/keyurparalkar)
|
||||
[](https://github.com/eco-monk)
|
||||
[](https://github.com/cokoghenun)
|
||||
[](https://github.com/vihar)
|
||||
[](https://github.com/ChandanBalajiBP)
|
||||
[](https://github.com/dhruvikn)
|
||||
[](https://github.com/berzerkeer)
|
||||
[](https://github.com/souma-ghosh)
|
||||
[](https://github.com/dhruvikn)
|
||||
[](https://github.com/tanvibhakta)
|
||||
[](https://github.com/subrata71)
|
||||
[](https://github.com/sum35h)
|
||||
[](https://github.com/tanvibhakta)
|
||||
[](https://github.com/sneha122)
|
||||
[](https://github.com/nsarupr)
|
||||
[](https://github.com/pratapaprasanna)
|
||||
[](https://github.com/sondermanish)
|
||||
[](https://github.com/Pranay105)
|
||||
[](https://github.com/vaibh1297)
|
||||
[](https://github.com/ankitsrivas14)
|
||||
[](https://github.com/NilanshBansal)
|
||||
[](https://github.com/ravikp7)
|
||||
[](https://github.com/gitstart-appsmith)
|
||||
[](https://github.com/kocharrahul7)
|
||||
[](https://github.com/rohitagarwal88)
|
||||
[](https://github.com/vaibh1297)
|
||||
[](https://github.com/Pranay105)
|
||||
[](https://github.com/NilanshBansal)
|
||||
[](https://github.com/ankitsrivas14)
|
||||
[](https://github.com/gitstart-appsmith)
|
||||
[](https://github.com/ravikp7)
|
||||
[](https://github.com/kocharrahul7)
|
||||
[](https://github.com/ramsaptami)
|
||||
[](https://github.com/AS-Laguna)
|
||||
[](https://github.com/vivonk)
|
||||
|
|
@ -238,7 +239,6 @@ Lets build great software together.
|
|||
[](https://github.com/tejasahluwalia)
|
||||
[](https://github.com/Vijetha-Kaja)
|
||||
[](https://github.com/appsmithguru)
|
||||
[](https://github.com/IAmAnubhavSaini)
|
||||
[](https://github.com/hiteshjoshi)
|
||||
[](https://github.com/rlnorthcutt)
|
||||
[](https://github.com/tomjose92)
|
||||
|
|
@ -334,6 +334,7 @@ Lets build great software together.
|
|||
[](https://github.com/Bhavin789)
|
||||
[](https://github.com/bhuvanaindukuri)
|
||||
[](https://github.com/donno2048)
|
||||
[](https://github.com/jacobwgillespie)
|
||||
[](https://github.com/reachtokish)
|
||||
[](https://github.com/nuwan94)
|
||||
[](https://github.com/OmkarPh)
|
||||
|
|
@ -341,6 +342,7 @@ Lets build great software together.
|
|||
[](https://github.com/rafaeelaudibert)
|
||||
[](https://github.com/samyakjain10)
|
||||
[](https://github.com/Jain-Sanchit)
|
||||
[](https://github.com/irfan-ansari-au28)
|
||||
[](https://github.com/sheetal2001p)
|
||||
[](https://github.com/Hard-Coder05)
|
||||
[](https://github.com/vj-codes)
|
||||
|
|
@ -370,7 +372,6 @@ Lets build great software together.
|
|||
[](https://github.com/felixsuarez0727)
|
||||
[](https://github.com/gitstart)
|
||||
[](https://github.com/ishaanmehta4)
|
||||
[](https://github.com/jacobwgillespie)
|
||||
[](https://github.com/JarLob)
|
||||
[](https://github.com/JeffResc)
|
||||
[](https://github.com/jmakhack)
|
||||
|
|
@ -421,6 +422,7 @@ Lets build great software together.
|
|||
[](https://github.com/nupur-singhal1992)
|
||||
[](https://github.com/nzidol)
|
||||
[](https://github.com/onifs10)
|
||||
[](https://github.com/ps-xaf)
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
230
app/client/cypress/fixtures/Templates/MockAppViewerUser.json
Normal file
230
app/client/cypress/fixtures/Templates/MockAppViewerUser.json
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
{
|
||||
"responseMeta": {
|
||||
"status": 200,
|
||||
"success": true
|
||||
},
|
||||
"data": {
|
||||
"user": {
|
||||
"id": "63abf1f3cf1ed12127ce3b01",
|
||||
"userPermissions": [],
|
||||
"name": "test1@sharklasers.com",
|
||||
"email": "test1@sharklasers.com",
|
||||
"source": "FORM",
|
||||
"isEnabled": true,
|
||||
"groupIds": [],
|
||||
"permissions": [],
|
||||
"isAnonymous": false,
|
||||
"tenantId": "63abe1a2cf1ed12127ce3ac4",
|
||||
"enabled": true,
|
||||
"username": "test1@sharklasers.com",
|
||||
"accountNonExpired": true,
|
||||
"accountNonLocked": true,
|
||||
"credentialsNonExpired": true,
|
||||
"claims": {},
|
||||
"address": {},
|
||||
"new": false
|
||||
},
|
||||
"workspaceApplications": [
|
||||
{
|
||||
"workspace": {
|
||||
"id": "63ad2c156e7a9012ada704c7",
|
||||
"userPermissions": [
|
||||
"inviteUsers:workspace",
|
||||
"read:workspaces",
|
||||
"execute:workspaceDatasources",
|
||||
"read:workspaceApplications"
|
||||
],
|
||||
"name": "Untitled workspace 1",
|
||||
"email": "test@sharklasers.com",
|
||||
"plugins": [
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ecf1ed12127ce3a5a",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1c5cf1ed12127ce3af5",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19fcf1ed12127ce3a69",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ecf1ed12127ce3a55",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1c5cf1ed12127ce3af4",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ccf1ed12127ce3a38",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19fcf1ed12127ce3a64",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1a0cf1ed12127ce3a92",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1c5cf1ed12127ce3af6",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ecf1ed12127ce3a4c",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1a1cf1ed12127ce3aa3",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1a3cf1ed12127ce3ae9",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ccf1ed12127ce3a39",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19fcf1ed12127ce3a6d",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ecf1ed12127ce3a5c",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe1a0cf1ed12127ce3a8a",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19fcf1ed12127ce3a84",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ccf1ed12127ce3a3a",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19fcf1ed12127ce3a79",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"userPermissions": [],
|
||||
"pluginId": "63abe19ecf1ed12127ce3a57",
|
||||
"status": "FREE",
|
||||
"new": true
|
||||
}
|
||||
],
|
||||
"slug": "untitled-workspace-1",
|
||||
"tenantId": "63abe1a2cf1ed12127ce3ac4",
|
||||
"logoUrl": "/api/v1/assets/null",
|
||||
"new": false
|
||||
},
|
||||
"applications": [
|
||||
{
|
||||
"id": "63ad2c166e7a9012ada704cb",
|
||||
"modifiedBy": "test@sharklasers.com",
|
||||
"userPermissions": [
|
||||
"canComment:applications",
|
||||
"read:applications"
|
||||
],
|
||||
"name": "Untitled application 1",
|
||||
"workspaceId": "63ad2c156e7a9012ada704c7",
|
||||
"isPublic": false,
|
||||
"pages": [
|
||||
{
|
||||
"id": "63ad2c166e7a9012ada704ce",
|
||||
"isDefault": true,
|
||||
"slug": "page1",
|
||||
"defaultPageId": "63ad2c166e7a9012ada704ce",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"appIsExample": false,
|
||||
"unreadCommentThreads": 0,
|
||||
"color": "#FBF4ED",
|
||||
"icon": "dollar",
|
||||
"slug": "untitled-application-1",
|
||||
"unpublishedCustomJSLibs": [],
|
||||
"publishedCustomJSLibs": [],
|
||||
"evaluationVersion": 2,
|
||||
"applicationVersion": 2,
|
||||
"isManualUpdate": true,
|
||||
"isAutoUpdate": false,
|
||||
"new": false,
|
||||
"modifiedAt": "2022-12-29T05:56:41.772Z"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"userId": "63abf1edcf1ed12127ce3af7",
|
||||
"username": "test@sharklasers.com",
|
||||
"name": "test@sharklasers.com",
|
||||
"permissionGroupName": "Administrator - Untitled workspace 1",
|
||||
"permissionGroupId": "63ad2c156e7a9012ada704c8"
|
||||
},
|
||||
{
|
||||
"userId": "63abf1f3cf1ed12127ce3b01",
|
||||
"username": "test1@sharklasers.com",
|
||||
"name": "test1@sharklasers.com",
|
||||
"permissionGroupName": "App Viewer - Untitled workspace 1",
|
||||
"permissionGroupId": "63ad2c156e7a9012ada704ca"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"newReleasesCount": "1",
|
||||
"releaseItems": [
|
||||
{
|
||||
"tagName": "v1.8.15",
|
||||
"name": "Release v1.8.15 🌈",
|
||||
"url": "https://github.com/appsmithorg/appsmith/releases/tag/v1.8.15",
|
||||
"descriptionHtml": "<h2>💪🏾 Improvements</h2>\n<ul>\n<li>Were your larger applications starting to feel like they took forever to load? We've shipped out a performance improvement to load these pages faster! [<a href=\"https://github.com/appsmithorg/appsmith/pull/19273\" data-hovercard-type=\"pull_request\" data-hovercard-url=\"/appsmithorg/appsmith/pull/19273/hovercard\">#19273</a>]</li>\n</ul>",
|
||||
"publishedAt": "2022-12-28T12:36:48Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
146
app/client/cypress/fixtures/jsFunctionTriggerDsl.json
Normal file
146
app/client/cypress/fixtures/jsFunctionTriggerDsl.json
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 4896.0,
|
||||
"snapColumns": 64.0,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0.0,
|
||||
"bottomRow": 1292.0,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 125.0,
|
||||
"parentRowSpace": 1.0,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 74.0,
|
||||
"minHeight": 1292.0,
|
||||
"dynamicTriggerPathList": [],
|
||||
"parentColumnSpace": 1.0,
|
||||
"dynamicBindingPathList": [],
|
||||
"leftColumn": 0.0,
|
||||
"children": [
|
||||
{
|
||||
"resetFormOnClick": false,
|
||||
"boxShadow": "none",
|
||||
"widgetName": "Button1",
|
||||
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg",
|
||||
"searchTags": ["click", "submit"],
|
||||
"topRow": 8.0,
|
||||
"bottomRow": 12.0,
|
||||
"parentRowSpace": 10.0,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"animateLoading": true,
|
||||
"parentColumnSpace": 10.0625,
|
||||
"dynamicTriggerPathList": [],
|
||||
"leftColumn": 7.0,
|
||||
"dynamicBindingPathList": [
|
||||
{ "key": "buttonColor" },
|
||||
{ "key": "borderRadius" },
|
||||
{ "key": "text" }
|
||||
],
|
||||
"text": "{{JSObject1.myFun1.data}}",
|
||||
"isDisabled": false,
|
||||
"key": "a1lbivvht8",
|
||||
"isDeprecated": false,
|
||||
"rightColumn": 23.0,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "wxkz5y9ypf",
|
||||
"isVisible": true,
|
||||
"recaptchaType": "V3",
|
||||
"version": 1.0,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"disabledWhenInvalid": false,
|
||||
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
"buttonVariant": "PRIMARY",
|
||||
"placement": "CENTER"
|
||||
},
|
||||
{
|
||||
"resetFormOnClick": false,
|
||||
"boxShadow": "none",
|
||||
"widgetName": "Button2",
|
||||
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg",
|
||||
"searchTags": ["click", "submit"],
|
||||
"topRow": 8.0,
|
||||
"bottomRow": 12.0,
|
||||
"parentRowSpace": 10.0,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"animateLoading": true,
|
||||
"parentColumnSpace": 10.0625,
|
||||
"dynamicTriggerPathList": [],
|
||||
"leftColumn": 39.0,
|
||||
"dynamicBindingPathList": [
|
||||
{ "key": "buttonColor" },
|
||||
{ "key": "borderRadius" },
|
||||
{ "key": "text" }
|
||||
],
|
||||
"text": "{{JSObject1.myFun2.data}}",
|
||||
"isDisabled": false,
|
||||
"key": "a1lbivvht8",
|
||||
"isDeprecated": false,
|
||||
"rightColumn": 55.0,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "ih110zq4c4",
|
||||
"isVisible": true,
|
||||
"recaptchaType": "V3",
|
||||
"version": 1.0,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"disabledWhenInvalid": false,
|
||||
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
"buttonVariant": "PRIMARY",
|
||||
"placement": "CENTER"
|
||||
},
|
||||
{
|
||||
"resetFormOnClick": false,
|
||||
"boxShadow": "none",
|
||||
"widgetName": "Button3",
|
||||
"onClick": "{{JSObject1.myFun2()\n}}",
|
||||
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||
"dynamicPropertyPathList": [{ "key": "onClick" }],
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg",
|
||||
"searchTags": ["click", "submit"],
|
||||
"topRow": 23.0,
|
||||
"bottomRow": 27.0,
|
||||
"parentRowSpace": 10.0,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"animateLoading": true,
|
||||
"parentColumnSpace": 10.0625,
|
||||
"dynamicTriggerPathList": [{ "key": "onClick" }],
|
||||
"leftColumn": 24.0,
|
||||
"dynamicBindingPathList": [
|
||||
{ "key": "buttonColor" },
|
||||
{ "key": "borderRadius" }
|
||||
],
|
||||
"text": "Submit",
|
||||
"isDisabled": false,
|
||||
"key": "a1lbivvht8",
|
||||
"isDeprecated": false,
|
||||
"rightColumn": 40.0,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "irxds8yzxq",
|
||||
"isVisible": true,
|
||||
"recaptchaType": "V3",
|
||||
"version": 1.0,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"disabledWhenInvalid": false,
|
||||
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
"buttonVariant": "PRIMARY",
|
||||
"placement": "CENTER"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
"type": "TEXT_WIDGET",
|
||||
"hideCard": false,
|
||||
"animateLoading": true,
|
||||
"useSourceData": false,
|
||||
"parentColumnSpace": 18.0625,
|
||||
"leftColumn": 22,
|
||||
"text": "Label",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
"type": "TEXT_WIDGET",
|
||||
"hideCard": false,
|
||||
"animateLoading": true,
|
||||
"useSourceData": false,
|
||||
"parentColumnSpace": 18.0625,
|
||||
"leftColumn": 22,
|
||||
"text": "Label",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
const dsl = require("../../../../fixtures/jsFunctionTriggerDsl.json");
|
||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
const agHelper = ObjectsRegistry.AggregateHelper;
|
||||
const jsEditor = ObjectsRegistry.JSEditor;
|
||||
const apiPage = ObjectsRegistry.ApiPage;
|
||||
const ee = ObjectsRegistry.EntityExplorer;
|
||||
|
||||
describe("JS data update on button click", function() {
|
||||
before(() => {
|
||||
agHelper.AddDsl(dsl);
|
||||
});
|
||||
|
||||
it("Populates js function data when triggered via button click", function() {
|
||||
apiPage.CreateAndFillApi(
|
||||
"https://jsonplaceholder.typicode.com/posts",
|
||||
"Api1",
|
||||
);
|
||||
|
||||
const jsObjectString = `export default {
|
||||
myVar1: [],
|
||||
myVar2: {},
|
||||
myFun1: async () => {
|
||||
//write code here
|
||||
const data = await Api1.run()
|
||||
return "myFun1 Data"
|
||||
},
|
||||
myFun2: async () => {
|
||||
//use async-await or promises
|
||||
await this.myFun1()
|
||||
return "myFun2 Data"
|
||||
}
|
||||
}`;
|
||||
|
||||
jsEditor.CreateJSObject(jsObjectString, {
|
||||
paste: true,
|
||||
completeReplace: true,
|
||||
toRun: false,
|
||||
shouldCreateNewJSObj: true,
|
||||
});
|
||||
ee.SelectEntityByName("Button2", "Widgets");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.AssertContains("myFun1 Data", "exist");
|
||||
agHelper.AssertContains("myFun2 Data", "exist");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
let dsName: any;
|
||||
|
||||
const agHelper = ObjectsRegistry.AggregateHelper,
|
||||
dataSources = ObjectsRegistry.DataSources;
|
||||
|
||||
describe("Bug 18664: datasource unsaved changes popup shows even without changes", function() {
|
||||
it("1. Create postgres datasource, save it and edit it and go back, now unsaved changes popup should not be shown", () => {
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
dataSources.CreatePlugIn("PostgreSQL");
|
||||
dsName = "Postgres" + uid;
|
||||
agHelper.RenameWithInPane(dsName, false);
|
||||
dataSources.SaveDatasource();
|
||||
cy.wait(1000);
|
||||
dataSources.EditDatasource();
|
||||
agHelper.GoBack();
|
||||
agHelper.AssertElementVisible(dataSources._activeDS);
|
||||
dataSources.DeleteDatasouceFromActiveTab(dsName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
const dataSources = ObjectsRegistry.DataSources;
|
||||
|
||||
describe("Testing empty datasource without saving should not throw 404", function() {
|
||||
it("Bug 19426: Create empty S3 datasource, test it", function() {
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
dataSources.CreatePlugIn("S3");
|
||||
dataSources.TestDatasource(false);
|
||||
dataSources.SaveDSFromDialog(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
let dsName: any;
|
||||
|
||||
const agHelper = ObjectsRegistry.AggregateHelper,
|
||||
dataSources = ObjectsRegistry.DataSources;
|
||||
|
||||
const testString = "test";
|
||||
|
||||
describe("datasource unsaved changes popup shows even without changes", function() {
|
||||
// In case of postgres and other plugins, host address and port key values are initialized by default making form dirty
|
||||
it("1. Bug 18664: Create postgres datasource, save it and edit it and go back, now unsaved changes popup should not be shown", () => {
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
// using CreatePlugIn function instead of CreateDatasource,
|
||||
// because I do not need to fill the datasource form and use the same default data
|
||||
dataSources.CreatePlugIn("PostgreSQL");
|
||||
dsName = "Postgres" + uid;
|
||||
agHelper.RenameWithInPane(dsName, false);
|
||||
dataSources.SaveDatasource();
|
||||
agHelper.Sleep();
|
||||
dataSources.EditDatasource();
|
||||
agHelper.GoBack();
|
||||
agHelper.AssertElementVisible(dataSources._activeDS);
|
||||
dataSources.DeleteDatasouceFromActiveTab(dsName);
|
||||
});
|
||||
});
|
||||
|
||||
// In case of Auth DS, headers, query parameters and custom query parameters are being initialized, which makes form dirty
|
||||
it("2. Bug 18962: Create REST API datasource, save it and edit it and go back, now unsaved changes popup should not be shown", () => {
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
// using CreatePlugIn function instead of CreateDatasource,
|
||||
// because I do not need to fill the datasource form and use the same default data
|
||||
dataSources.CreatePlugIn("Authenticated API");
|
||||
dsName = "AuthDS" + uid;
|
||||
agHelper.RenameWithInPane(dsName, false);
|
||||
dataSources.FillAuthAPIUrl();
|
||||
dataSources.SaveDatasource();
|
||||
agHelper.Sleep();
|
||||
|
||||
// Edit DS for the first time, we shouldnt see discard popup on back button
|
||||
// Even if headers, and query parameters are being initialized, we shouldnt see the popup
|
||||
// as those are not initialized by user
|
||||
dataSources.EditDatasource();
|
||||
agHelper.GoBack();
|
||||
agHelper.AssertElementVisible(dataSources._activeDS);
|
||||
|
||||
// Edit DS from active tab and add oauth2 details
|
||||
dataSources.EditDSFromActiveTab(dsName);
|
||||
dataSources.AddOAuth2AuthorizationCodeDetails(
|
||||
testString,
|
||||
testString,
|
||||
testString,
|
||||
testString,
|
||||
);
|
||||
dataSources.UpdateDatasource();
|
||||
agHelper.Sleep();
|
||||
|
||||
// Now edit DS, and ensure that discard popup is not shown on back button click
|
||||
// Even if custom authentication params are being initialized, we shouldnt see the popup
|
||||
// as those are not initialized by user
|
||||
dataSources.EditDatasource();
|
||||
agHelper.GoBack();
|
||||
agHelper.AssertElementVisible(dataSources._activeDS);
|
||||
|
||||
dataSources.DeleteDatasouceFromActiveTab(dsName);
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Bug 18998: Create mongoDB datasource, save it and edit it and change connection URI param, discard popup should be shown as user has made valid change", () => {
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
// using CreatePlugIn function instead of CreateDatasource,
|
||||
// because I do not need to fill the datasource form and use the same default data
|
||||
dataSources.CreatePlugIn("MongoDB");
|
||||
dsName = "Mongo" + uid;
|
||||
agHelper.RenameWithInPane(dsName, false);
|
||||
dataSources.FillMongoDSForm();
|
||||
dataSources.SaveDatasource();
|
||||
agHelper.Sleep();
|
||||
|
||||
// Edit datasource, change connection string uri param and click on back button
|
||||
dataSources.EditDatasource();
|
||||
dataSources.FillMongoDatasourceFormWithURI(testString);
|
||||
|
||||
// Assert that popup is visible
|
||||
dataSources.SaveDSFromDialog(false);
|
||||
|
||||
dataSources.DeleteDatasouceFromActiveTab(dsName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -166,7 +166,7 @@ describe("MaintainContext&Focus", function() {
|
|||
it("9. Datasource edit mode has to be maintained", () => {
|
||||
ee.SelectEntityByName("Appsmith", "Datasources");
|
||||
dataSources.EditDatasource();
|
||||
dataSources.SaveDSFromDialog(false);
|
||||
agHelper.GoBack();
|
||||
ee.SelectEntityByName("Github", "Datasources");
|
||||
dataSources.AssertViewMode();
|
||||
ee.SelectEntityByName("Appsmith", "Datasources");
|
||||
|
|
@ -175,7 +175,7 @@ describe("MaintainContext&Focus", function() {
|
|||
|
||||
it("10. Datasource collapse state has to be maintained", () => {
|
||||
// Create datasource 1
|
||||
dataSources.SaveDSFromDialog(false);
|
||||
agHelper.GoBack();
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
dataSources.CreatePlugIn("PostgreSQL");
|
||||
agHelper.RenameWithInPane("Postgres1", false);
|
||||
|
|
@ -197,7 +197,7 @@ describe("MaintainContext&Focus", function() {
|
|||
dataSources.AssertSectionCollapseState(1, false);
|
||||
});
|
||||
|
||||
it("10. Maintain focus of form control inputs", () => {
|
||||
it("11. Maintain focus of form control inputs", () => {
|
||||
ee.SelectEntityByName("SQL_Query");
|
||||
dataSources.ToggleUsePreparedStatement(false);
|
||||
cy.SearchEntityandOpen("S3_Query");
|
||||
|
|
@ -207,7 +207,8 @@ describe("MaintainContext&Focus", function() {
|
|||
cy.SearchEntityandOpen("SQL_Query");
|
||||
cy.get(".t--form-control-SWITCH input").should("be.focused");
|
||||
cy.SearchEntityandOpen("S3_Query");
|
||||
cy.get(queryLocators.querySettingsTab).click();
|
||||
agHelper.Sleep();
|
||||
agHelper.GetNClick(dataSources._queryResponse("SETTINGS"));
|
||||
cy.xpath(queryLocators.queryTimeout).should("be.focused");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ describe("Creating new app after discontinuing guided tour should not start the
|
|||
cy.get(commonlocators.homeIcon)
|
||||
.click({ force: true })
|
||||
.wait(8000); //for page to settle!
|
||||
datasources.CloseReconnectDataSourceModal() // Check if reconnect data source modal is visible and close it
|
||||
datasources.CloseReconnectDataSourceModal(); // Check if reconnect data source modal is visible and close it
|
||||
cy.get(guidedTourLocators.welcomeTour)
|
||||
.click()
|
||||
.wait(2000);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
const commonlocators = require("../../../../locators/commonlocators.json");
|
||||
const templateLocators = require("../../../../locators/TemplatesLocators.json");
|
||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
const { AggregateHelper, HomePage } = ObjectsRegistry;
|
||||
|
||||
describe("Fork a template to an workspace", () => {
|
||||
it("Fork a template to an workspace", () => {
|
||||
|
|
@ -30,4 +32,21 @@ describe("Fork a template to an workspace", () => {
|
|||
expect(location.search).to.eq("?showForkTemplateModal=true");
|
||||
});
|
||||
});
|
||||
it("Hide template fork button if user does not have a valid workspace to fork", () => {
|
||||
HomePage.NavigateToHome();
|
||||
// Mock user with App Viewer permission
|
||||
cy.intercept("/api/v1/applications/new", {
|
||||
fixture: "Templates/MockAppViewerUser.json",
|
||||
});
|
||||
AggregateHelper.RefreshPage();
|
||||
HomePage.SwitchToTemplatesTab();
|
||||
AggregateHelper.AssertElementExist(templateLocators.templateCard);
|
||||
AggregateHelper.AssertElementAbsence(templateLocators.templateForkButton);
|
||||
|
||||
AggregateHelper.GetNClick(templateLocators.templateCard);
|
||||
AggregateHelper.AssertElementExist(templateLocators.templateCard);
|
||||
AggregateHelper.AssertElementAbsence(
|
||||
templateLocators.templateViewForkButton,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -819,8 +819,8 @@ describe("App Theming funtionality", function() {
|
|||
|
||||
//Change Border & verify
|
||||
|
||||
cy.get(".t--button-tab-0px").click();
|
||||
cy.get(".t--button-tab-0px")
|
||||
cy.get(".t--button-group-0px").click();
|
||||
cy.get(".t--button-group-0px")
|
||||
.eq(0)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
|
|
@ -842,8 +842,8 @@ describe("App Theming funtionality", function() {
|
|||
});
|
||||
|
||||
//Change Shadow & verify
|
||||
cy.get(".t--button-tab-0.10px").click();
|
||||
cy.get(".t--button-tab-0.10px div")
|
||||
cy.get(".t--button-group-0.10px").click();
|
||||
cy.get(".t--button-group-0.10px div")
|
||||
.eq(0)
|
||||
.invoke("css", "box-shadow")
|
||||
.then((boxshadow) => {
|
||||
|
|
@ -1051,10 +1051,10 @@ describe("App Theming funtionality", function() {
|
|||
|
||||
//Change Border & verify
|
||||
|
||||
cy.get(".t--button-tab-0\\.375rem")
|
||||
cy.get(".t--button-group-0\\.375rem")
|
||||
.click()
|
||||
.wait(500);
|
||||
cy.get(".t--button-tab-0\\.375rem div")
|
||||
cy.get(".t--button-group-0\\.375rem div")
|
||||
.eq(0)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
|
|
@ -1076,10 +1076,10 @@ describe("App Theming funtionality", function() {
|
|||
});
|
||||
|
||||
//Change Shadow & verify
|
||||
cy.get(".t--button-tab-0.1px")
|
||||
cy.get(".t--button-group-0.1px")
|
||||
.click()
|
||||
.wait(500);
|
||||
cy.get(".t--button-tab-0.1px div")
|
||||
cy.get(".t--button-group-0.1px div")
|
||||
.invoke("css", "box-shadow")
|
||||
.then((boxshadow) => {
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ describe("In a button group widget, menu button width", function() {
|
|||
const menuButtonId = "groupButton1";
|
||||
// Change the first button type to menu
|
||||
cy.editColumn(menuButtonId);
|
||||
cy.get(".t--button-tab-MENU").click({ force: true });
|
||||
cy.get(".t--button-group-MENU").click({ force: true });
|
||||
cy.get(".t--add-menu-item-btn").click();
|
||||
// Get the newly converted menu button
|
||||
cy.get(`.appsmith_widget_${widgetId} div.t--buttongroup-widget`)
|
||||
|
|
@ -126,7 +126,7 @@ describe("In a button group widget, menu button width", function() {
|
|||
.click();
|
||||
cy.moveToStyleTab();
|
||||
// Change its orientation to vetical
|
||||
cy.get(".t--button-tab-vertical").click({ force: true });
|
||||
cy.get(".t--button-group-vertical").click({ force: true });
|
||||
// Get the default menu button
|
||||
cy.get(`.appsmith_widget_${widgetId} div.t--buttongroup-widget`)
|
||||
.children()
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ describe("Button Group Widget Functionality", function() {
|
|||
|
||||
it("Update icon alignment and Verify buttons alignments", function() {
|
||||
// align right
|
||||
cy.get(".t--property-control-position .t--button-tab-left")
|
||||
cy.get(".t--property-control-position .t--button-group-left")
|
||||
.first()
|
||||
.click();
|
||||
cy.wait(200);
|
||||
|
|
@ -106,7 +106,7 @@ describe("Button Group Widget Functionality", function() {
|
|||
.eq(1)
|
||||
.should("have.css", "flex-direction", "row");
|
||||
// align left
|
||||
cy.get(".t--property-control-position .t--button-tab-right")
|
||||
cy.get(".t--property-control-position .t--button-group-right")
|
||||
.last()
|
||||
.click();
|
||||
cy.wait(200);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ describe("Button Widget Functionality", function() {
|
|||
// Assert if the icon exists
|
||||
cy.get(`${widgetsPage.buttonWidget} .bp3-icon-add`).should("exist");
|
||||
// Change icon alignment to right
|
||||
cy.get(`${iconAlignmentProperty} .t--button-tab-right`)
|
||||
cy.get(`${iconAlignmentProperty} .t--button-group-right`)
|
||||
.last()
|
||||
.click({
|
||||
force: true,
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ describe("Code Scanner widget's functionality", () => {
|
|||
|
||||
// Select scanner layout as CLICK_TO_SCAN
|
||||
cy.get(
|
||||
`${commonlocators.codeScannerScannerLayout} .t--button-tab-CLICK_TO_SCAN`,
|
||||
`${commonlocators.codeScannerScannerLayout} .t--button-group-CLICK_TO_SCAN`,
|
||||
)
|
||||
.last()
|
||||
.click({
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe("Checkbox Widget Functionality", function() {
|
|||
);
|
||||
|
||||
// align right
|
||||
cy.get(".t--property-control-alignment .t--button-tab-RIGHT")
|
||||
cy.get(".t--property-control-alignment .t--button-group-RIGHT")
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.checkboxWidget + " " + ".t--checkbox-widget-label").should(
|
||||
|
|
@ -63,7 +63,7 @@ describe("Checkbox Widget Functionality", function() {
|
|||
.last()
|
||||
.click({ force: true });
|
||||
cy.wait(200);
|
||||
cy.get(".t--button-tab-Left").click({ force: true });
|
||||
cy.get(".t--button-group-Left").click({ force: true });
|
||||
cy.wait(200);
|
||||
cy.PublishtheApp();
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ describe("Checkbox Widget Functionality", function() {
|
|||
it("6. Checkbox Functionality To change label style of checkbox", function() {
|
||||
cy.openPropertyPane("checkboxwidget");
|
||||
cy.moveToStyleTab();
|
||||
cy.get(".t--property-control-emphasis .t--button-tab-BOLD").click({
|
||||
cy.get(".t--property-control-emphasis .t--button-group-BOLD").click({
|
||||
force: true,
|
||||
});
|
||||
cy.PublishtheApp();
|
||||
|
|
|
|||
|
|
@ -190,4 +190,54 @@ describe("JSON Form Widget Form Bindings", () => {
|
|||
|
||||
cy.get(publishPage.backToEditor).click({ force: true });
|
||||
});
|
||||
|
||||
it("8. Form value should contain hidden fields value if useSourceData is set to true", () => {
|
||||
cy.addDsl(dslWithoutSchema);
|
||||
|
||||
const schema = {
|
||||
name: "",
|
||||
age: 10,
|
||||
};
|
||||
|
||||
cy.openPropertyPane("jsonformwidget");
|
||||
cy.testJsontext("sourcedata", JSON.stringify(schema));
|
||||
|
||||
cy.togglebar(`${propertyControlPrefix}-usesourcedata input`);
|
||||
|
||||
cy.openFieldConfiguration("age");
|
||||
cy.togglebarDisable(`${propertyControlPrefix}-visible input`);
|
||||
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{JSON.stringify(JSONForm1.formData)}}");
|
||||
|
||||
cy.get(".t--widget-textwidget .bp3-ui-text").contains(
|
||||
JSON.stringify(schema),
|
||||
);
|
||||
});
|
||||
|
||||
it("9. Form value should not contain hidden fields value if useSourceData is set to false", () => {
|
||||
cy.addDsl(dslWithoutSchema);
|
||||
|
||||
const name = "JOHN";
|
||||
|
||||
const schema = {
|
||||
name,
|
||||
age: 10,
|
||||
};
|
||||
|
||||
cy.openPropertyPane("jsonformwidget");
|
||||
cy.testJsontext("sourcedata", JSON.stringify(schema));
|
||||
|
||||
cy.togglebarDisable(`${propertyControlPrefix}-usesourcedata input`);
|
||||
|
||||
cy.openFieldConfiguration("age");
|
||||
cy.togglebarDisable(`${propertyControlPrefix}-visible input`);
|
||||
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{JSON.stringify(JSONForm1.formData)}}");
|
||||
|
||||
cy.get(".t--widget-textwidget .bp3-ui-text").contains(
|
||||
JSON.stringify({ name }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe("Menu Button Widget Functionality", () => {
|
|||
// Assert if the icon exists
|
||||
cy.get(`${formWidgetsPage.menuButtonWidget} .bp3-icon-add`).should("exist");
|
||||
// Change its icon alignment to right
|
||||
cy.get(".t--property-control-position .t--button-tab-right")
|
||||
cy.get(".t--property-control-position .t--button-group-right")
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.wait(200);
|
||||
|
|
@ -110,7 +110,9 @@ describe("Menu Button Widget Functionality", () => {
|
|||
cy.moveToContentTab();
|
||||
|
||||
// Select menu items source as Dynamic
|
||||
cy.get(`${commonlocators.menuButtonMenuItemsSource} .t--button-tab-DYNAMIC`)
|
||||
cy.get(
|
||||
`${commonlocators.menuButtonMenuItemsSource} .t--button-group-DYNAMIC`,
|
||||
)
|
||||
.last()
|
||||
.click({
|
||||
force: true,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ describe("Progress Widget", function() {
|
|||
// Circular progress
|
||||
it("Property: type, Change type to Circular", function() {
|
||||
// Switch to circular mode
|
||||
cy.get(".t--button-tab-circular").click({ force: true });
|
||||
cy.get(".t--button-group-circular").click({ force: true });
|
||||
cy.get("[data-cy='circular']").should("exist");
|
||||
});
|
||||
it("Property: isIndeterminate, Toggle infinite loading", function() {
|
||||
|
|
|
|||
|
|
@ -246,10 +246,10 @@ describe("RichTextEditor Widget Functionality", function() {
|
|||
|
||||
// Changing the input type to markdown and again testing the cursor position
|
||||
cy.openPropertyPane("richtexteditorwidget");
|
||||
cy.get(".t--button-tab-markdown").click({ force: true });
|
||||
cy.get(".t--button-group-markdown").click({ force: true });
|
||||
setRTEContent(testString);
|
||||
testCursorPoistion(testStringLen, tinyMceId);
|
||||
cy.get(".t--button-tab-html").click({ force: true });
|
||||
cy.get(".t--button-group-html").click({ force: true });
|
||||
});
|
||||
|
||||
it("13. Check if different font size texts are supported inside the RTE widget", function() {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ describe("Switch Widget Functionality", function() {
|
|||
"left",
|
||||
);
|
||||
// align right
|
||||
cy.get(".t--property-control-alignment .t--button-tab-RIGHT")
|
||||
cy.get(".t--property-control-alignment .t--button-group-RIGHT")
|
||||
.first()
|
||||
.click();
|
||||
cy.wait(200);
|
||||
|
|
@ -106,7 +106,7 @@ describe("Switch Widget Functionality", function() {
|
|||
.last()
|
||||
.click({ force: true });
|
||||
cy.wait(200);
|
||||
cy.get(".t--button-tab-Left").click({ force: true });
|
||||
cy.get(".t--button-group-Left").click({ force: true });
|
||||
cy.wait(200);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.switchwidget + " " + ".bp3-align-right").should("exist");
|
||||
|
|
@ -150,7 +150,7 @@ describe("Switch Widget Functionality", function() {
|
|||
it("11. Switch Functionality To change label style of switch", function() {
|
||||
cy.openPropertyPane("switchwidget");
|
||||
cy.moveToStyleTab();
|
||||
cy.get(".t--property-control-emphasis .t--button-tab-BOLD").click({
|
||||
cy.get(".t--property-control-emphasis .t--button-group-BOLD").click({
|
||||
force: true,
|
||||
});
|
||||
cy.PublishtheApp();
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ describe("Table Widget Image Resize feature validation", function() {
|
|||
cy.editColumn("image");
|
||||
cy.moveToStyleTab();
|
||||
|
||||
cy.get(".t--button-tab-MEDIUM").click();
|
||||
cy.get(".t--button-group-MEDIUM").click();
|
||||
cy.getTableV2DataSelector("1", "3").then((selector) => {
|
||||
cy.get(`${selector} img`).should("have.css", "height", "64px");
|
||||
});
|
||||
|
||||
cy.get(".t--button-tab-LARGE").click();
|
||||
cy.get(".t--button-group-LARGE").click();
|
||||
cy.getTableV2DataSelector("1", "3").then((selector) => {
|
||||
cy.get(`${selector} img`).should("have.css", "height", "128px");
|
||||
});
|
||||
|
||||
cy.get(".t--button-tab-DEFAULT").click();
|
||||
cy.get(".t--button-group-DEFAULT").click();
|
||||
cy.getTableV2DataSelector("1", "3").then((selector) => {
|
||||
cy.get(`${selector} img`).should("have.css", "height", "32px");
|
||||
});
|
||||
|
|
@ -47,17 +47,17 @@ describe("Table Widget Image Resize feature validation", function() {
|
|||
cy.editColumn("image");
|
||||
cy.moveToStyleTab();
|
||||
|
||||
cy.get(".t--button-tab-MEDIUM").click();
|
||||
cy.get(".t--button-group-MEDIUM").click();
|
||||
cy.getTableV2DataSelector("1", "3").then((selector) => {
|
||||
cy.get(`${selector} img`).should("have.css", "height", "64px");
|
||||
});
|
||||
|
||||
cy.get(".t--button-tab-LARGE").click();
|
||||
cy.get(".t--button-group-LARGE").click();
|
||||
cy.getTableV2DataSelector("1", "3").then((selector) => {
|
||||
cy.get(`${selector} img`).should("have.css", "height", "128px");
|
||||
});
|
||||
|
||||
cy.get(".t--button-tab-DEFAULT").click();
|
||||
cy.get(".t--button-group-DEFAULT").click();
|
||||
cy.getTableV2DataSelector("1", "3").then((selector) => {
|
||||
cy.get(`${selector} img`).should("have.css", "height", "32px");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -307,26 +307,26 @@ describe("Table widget inline editing functionality", () => {
|
|||
cy.get(".t--property-control-updatemode .bp3-popover-target")
|
||||
.last()
|
||||
.click();
|
||||
cy.get(".t--button-tab-CUSTOM").click({ force: true });
|
||||
cy.get(".t--button-group-CUSTOM").click({ force: true });
|
||||
cy.get("[data-rbd-draggable-id='EditActions1']").should("not.exist");
|
||||
cy.makeColumnEditable("task");
|
||||
cy.get("[data-rbd-draggable-id='EditActions1']").should("not.exist");
|
||||
cy.get(".t--property-control-updatemode .bp3-popover-target")
|
||||
.last()
|
||||
.click();
|
||||
cy.get(".t--button-tab-ROW_LEVEL").click({ force: true });
|
||||
cy.get(".t--button-group-ROW_LEVEL").click({ force: true });
|
||||
cy.get("[data-rbd-draggable-id='EditActions1']").should("exist");
|
||||
cy.get(".t--property-control-updatemode .bp3-popover-target")
|
||||
.last()
|
||||
.click();
|
||||
cy.get(".t--button-tab-CUSTOM").click({ force: true });
|
||||
cy.get(".t--button-group-CUSTOM").click({ force: true });
|
||||
cy.get("[data-rbd-draggable-id='EditActions1']").should("not.exist");
|
||||
cy.makeColumnEditable("step");
|
||||
cy.makeColumnEditable("task");
|
||||
cy.get(".t--property-control-updatemode .bp3-popover-target")
|
||||
.last()
|
||||
.click();
|
||||
cy.get(".t--button-tab-ROW_LEVEL").click({ force: true });
|
||||
cy.get(".t--button-group-ROW_LEVEL").click({ force: true });
|
||||
cy.get("[data-rbd-draggable-id='EditActions1']").should("not.exist");
|
||||
});
|
||||
|
||||
|
|
@ -787,7 +787,7 @@ describe("Table widget inline editing functionality", () => {
|
|||
cy.openPropertyPane("tablewidgetv2");
|
||||
|
||||
cy.makeColumnEditable("step");
|
||||
cy.get(".t--button-tab-CUSTOM").click({ force: true });
|
||||
cy.get(".t--button-group-CUSTOM").click({ force: true });
|
||||
cy.wait(1000);
|
||||
|
||||
// case 1: check if updatedRowIndex is 0, when cell at row 0 is updated.
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ describe("Table Widget property pane feature validation", function() {
|
|||
cy.get(widgetsPage.rowHeight)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(".t--button-tab-SHORT").click({ force: true });
|
||||
cy.get(".t--button-group-SHORT").click({ force: true });
|
||||
cy.wait(2000);
|
||||
cy.PublishtheApp();
|
||||
cy.readTableV2dataValidateCSS("0", "1", "height", "29px", true);
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ describe("Table Widget V2 Functionality", function() {
|
|||
|
||||
cy.get(".t--property-pane-back-btn").click();
|
||||
cy.makeColumnEditable("step");
|
||||
cy.get(".t--button-tab-ROW_LEVEL").click();
|
||||
cy.get(".t--button-group-ROW_LEVEL").click();
|
||||
cy.get(".t--table-filter-columns-dropdown").click();
|
||||
cy.get(".t--dropdown-option").should("not.contain", "Save / Discard");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,29 @@ describe("Table Widget text wrapping functionality", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("2. should check that other cells in the row is not wrapped when one of the cell is wrapped", () => {
|
||||
it("2. should check that a tooltip is shown when hovered on a ellipsised content", () => {
|
||||
cy.get(
|
||||
`.td[data-colindex=2][data-rowindex=0] .t--table-cell-tooltip-target`,
|
||||
).trigger("mouseenter");
|
||||
|
||||
cy.get(".bp3-tooltip").should("exist");
|
||||
cy.get(".bp3-tooltip .bp3-popover-content").should(
|
||||
"contain",
|
||||
"michael.lawson@reqres.in",
|
||||
);
|
||||
|
||||
cy.get(
|
||||
`.td[data-colindex=2][data-rowindex=1] .t--table-cell-tooltip-target`,
|
||||
).trigger("mouseenter", { force: true });
|
||||
|
||||
cy.get(".bp3-tooltip").should("exist");
|
||||
cy.get(".bp3-tooltip .bp3-popover-content").should(
|
||||
"contain",
|
||||
"lindsay.ferguson@reqres.in",
|
||||
);
|
||||
});
|
||||
|
||||
it("3. should check that other cells in the row is not wrapped when one of the cell is wrapped", () => {
|
||||
cy.getTableCellHeight(2, 0).then((height) => {
|
||||
expect(height).to.equal("28px");
|
||||
});
|
||||
|
|
@ -52,7 +74,7 @@ describe("Table Widget text wrapping functionality", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("3. should check that cell wrapping option is only available for plain text, number, date and URL", () => {
|
||||
it("4. should check that cell wrapping option is only available for plain text, number, date and URL", () => {
|
||||
cy.openPropertyPane("tablewidgetv2");
|
||||
cy.editColumn("email");
|
||||
[
|
||||
|
|
@ -105,7 +127,7 @@ describe("Table Widget text wrapping functionality", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("4. should check that plain text, number, date and URL column is getting wrapped when cell wrapping is enabled", () => {
|
||||
it("5. should check that plain text, number, date and URL column is getting wrapped when cell wrapping is enabled", () => {
|
||||
cy.openPropertyPane("tablewidgetv2");
|
||||
cy.editColumn("id");
|
||||
|
||||
|
|
@ -134,7 +156,7 @@ describe("Table Widget text wrapping functionality", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("5. should check that pageSize does not change when cell wrapping is enabled", () => {
|
||||
it("6. should check that pageSize does not change when cell wrapping is enabled", () => {
|
||||
cy.openPropertyPane("tablewidgetv2");
|
||||
cy.editColumn("image");
|
||||
let pageSizeBeforeWrapping;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ describe("Checkbox column type funtionality test", () => {
|
|||
.contains("STYLE")
|
||||
.click({ force: true });
|
||||
// Check horizontal alignment
|
||||
cy.get(".t--property-control-horizontalalignment .t--button-tab-CENTER")
|
||||
cy.get(".t--property-control-horizontalalignment .t--button-group-CENTER")
|
||||
.first()
|
||||
.click();
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ describe("Checkbox column type funtionality test", () => {
|
|||
});
|
||||
|
||||
// Check vertical alignment
|
||||
cy.get(".t--property-control-verticalalignment .t--button-tab-BOTTOM")
|
||||
cy.get(".t--property-control-verticalalignment .t--button-group-BOTTOM")
|
||||
.first()
|
||||
.click();
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ describe("Switch column type funtionality test", () => {
|
|||
.contains("STYLE")
|
||||
.click({ force: true });
|
||||
// Check horizontal alignment
|
||||
cy.get(".t--property-control-horizontalalignment .t--button-tab-CENTER")
|
||||
cy.get(".t--property-control-horizontalalignment .t--button-group-CENTER")
|
||||
.first()
|
||||
.click();
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ describe("Switch column type funtionality test", () => {
|
|||
});
|
||||
|
||||
// Check vertical alignment
|
||||
cy.get(".t--property-control-verticalalignment .t--button-tab-BOTTOM")
|
||||
cy.get(".t--property-control-verticalalignment .t--button-group-BOTTOM")
|
||||
.first()
|
||||
.click();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ describe("Table widget v2", function() {
|
|||
cy.openPropertyPane("tablewidgetv2");
|
||||
|
||||
cy.moveToStyleTab();
|
||||
cy.get(".t--button-tab-SHORT").click({ force: true });
|
||||
cy.get(".t--button-group-SHORT").click({ force: true });
|
||||
cy.get(".t--widget-textwidget .bp3-ui-text").should("contain", "7");
|
||||
|
||||
cy.get(".t--button-tab-DEFAULT").click({ force: true });
|
||||
cy.get(".t--button-group-DEFAULT").click({ force: true });
|
||||
cy.get(".t--widget-textwidget .bp3-ui-text").should("contain", "5");
|
||||
|
||||
cy.get(".t--button-tab-TALL").click({ force: true });
|
||||
cy.get(".t--button-group-TALL").click({ force: true });
|
||||
cy.get(".t--widget-textwidget .bp3-ui-text").should("contain", "4");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ describe("Text Widget color/font/alignment Functionality", function() {
|
|||
|
||||
it("Test to validate enable scroll feature", function() {
|
||||
cy.moveToContentTab();
|
||||
cy.get(".t--button-tab-SCROLL").click({ force: true });
|
||||
cy.get(".t--button-group-SCROLL").click({ force: true });
|
||||
cy.wait("@updateLayout");
|
||||
cy.get(commonlocators.headingTextStyle).trigger("mouseover", {
|
||||
force: true,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ describe("Text Widget Truncate Functionality", function() {
|
|||
|
||||
it("Check default overflow property is No overflow", function() {
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.get(".t--button-tab-NONE")
|
||||
cy.get(".t--button-group-NONE")
|
||||
.last()
|
||||
.should("have.attr", "aria-selected", "true");
|
||||
cy.closePropertyPane();
|
||||
|
|
@ -34,7 +34,7 @@ describe("Text Widget Truncate Functionality", function() {
|
|||
it("Enable Truncate Text option and Validate", function() {
|
||||
cy.wait(2000);
|
||||
cy.get("body").type("{esc}");
|
||||
cy.get(".t--button-tab-TRUNCATE").click({ force: true });
|
||||
cy.get(".t--button-group-TRUNCATE").click({ force: true });
|
||||
cy.wait("@updateLayout");
|
||||
cy.get(
|
||||
`.appsmith_widget_${dsl.dsl.children[0].widgetId} .t--widget-textwidget-truncate`,
|
||||
|
|
|
|||
|
|
@ -166,4 +166,4 @@ describe("Widget Copy paste", function() {
|
|||
//verify a pasted list widget
|
||||
cy.get(widgetsPage.listWidget).should("have.length", 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -63,10 +63,8 @@ describe("MySQL noise test", function() {
|
|||
expect(response.body.data.statusCode).to.eq("200 OK");
|
||||
});
|
||||
cy.wait("@postExecute").then(({ response }) => {
|
||||
expect(response.body.data.statusCode).to.eq("5004");
|
||||
expect(response.body.data.title).to.eq(
|
||||
"Datasource configuration is invalid",
|
||||
);
|
||||
expect(response.body.data.statusCode).to.eq("5000");
|
||||
expect(response.body.data.title).to.eq("Query execution error");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -437,13 +437,15 @@ describe("JS Function Execution", function() {
|
|||
|
||||
it("9. Bug 13197: Verify converting async functions to sync resets all settings", () => {
|
||||
const asyncJSCode = `export default {
|
||||
name: "Appsmith",
|
||||
asyncToSync : async ()=>{
|
||||
return "yes";`;
|
||||
|
||||
const syncJSCode = `export default {
|
||||
name: "Appsmith",
|
||||
asyncToSync : ()=>{
|
||||
return "yes";
|
||||
}
|
||||
},
|
||||
}`;
|
||||
|
||||
jsEditor.CreateJSObject(asyncJSCode, {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe("JSObjects OnLoad Actions tests", function() {
|
|||
AssertJSOnPageLoad(
|
||||
"runWorldCountries",
|
||||
false,
|
||||
"UncaughtPromiseRejection: getWorldCountries is not defined",
|
||||
"ReferenceError: getWorldCountries is not defined",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -51,7 +51,7 @@ describe("JSObjects OnLoad Actions tests", function() {
|
|||
AssertJSOnPageLoad(
|
||||
"runWorldCountries",
|
||||
false,
|
||||
"UncaughtPromiseRejection: getWorldCountries is not defined",
|
||||
"ReferenceError: getWorldCountries is not defined",
|
||||
);
|
||||
|
||||
homePage.NavigateToHome();
|
||||
|
|
@ -59,7 +59,7 @@ describe("JSObjects OnLoad Actions tests", function() {
|
|||
AssertJSOnPageLoad(
|
||||
"runWorldCountries",
|
||||
false,
|
||||
"UncaughtPromiseRejection: getWorldCountries is not defined",
|
||||
"ReferenceError: getWorldCountries is not defined",
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ describe("JSObjects OnLoad Actions tests", function() {
|
|||
function AssertJSOnPageLoad(
|
||||
jsMethod: string,
|
||||
shouldCheckImport = false,
|
||||
faliureMsg: string = "",
|
||||
faliureMsg = "",
|
||||
) {
|
||||
agHelper.AssertElementVisible(
|
||||
jsEditor._dialogBody("JSObject1." + jsMethod),
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe("Cyclic Dependency Informational Error Messagaes", function() {
|
|||
.last()
|
||||
.find(`${datasource.createQuery}`)
|
||||
.click({ force: true });
|
||||
|
||||
|
||||
//Step5.1: Click the editing field
|
||||
cy.get(".t--action-name-edit-field").click({ force: true });
|
||||
|
||||
|
|
@ -170,4 +170,4 @@ describe("Cyclic Dependency Informational Error Messagaes", function() {
|
|||
1,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
"deleteWidget": ".t--modal-widget>div .t--widget-delete-control",
|
||||
"textbuttonWidget": ".t--draggable-buttonwidget button.bp3-button[type='button']",
|
||||
"textInputval": ".t--draggable-textwidget span.t--widget-name",
|
||||
"textCenterAlign": ".t--property-control-alignment .t--button-tab-CENTER",
|
||||
"textCenterAlign": ".t--property-control-alignment .t--button-group-CENTER",
|
||||
"ColumnAction": ".t--property-control-rowbutton button",
|
||||
"SearchTextChangeAction": ".t--property-control-onsearchtextchanged button",
|
||||
"tableSearchTextChangeSelected": ".t--property-control-onsearchtextchanged",
|
||||
|
|
@ -86,15 +86,15 @@
|
|||
"editCreatedColumn": ".t--property-control-createdcolumns input",
|
||||
"alignOpt": ".t--dropdown-option",
|
||||
"tableCol": ".draggable-header ",
|
||||
"centerAlign": ".t--button-tab-CENTER",
|
||||
"rightAlign": ".t--button-tab-RIGHT",
|
||||
"leftAlign": ".t--button-tab-LEFT",
|
||||
"bold": ".t--button-tab-BOLD",
|
||||
"italics": ".t--button-tab-ITALIC",
|
||||
"underline": ".t--button-tab-UNDERLINE",
|
||||
"verticalTop": ".t--button-tab-TOP",
|
||||
"verticalCenter": ".t--button-tab-CENTER",
|
||||
"verticalBottom": ".t--button-tab-BOTTOM",
|
||||
"centerAlign": ".t--button-group-CENTER",
|
||||
"rightAlign": ".t--button-group-RIGHT",
|
||||
"leftAlign": ".t--button-group-LEFT",
|
||||
"bold": ".t--button-group-BOLD",
|
||||
"italics": ".t--button-group-ITALIC",
|
||||
"underline": ".t--button-group-UNDERLINE",
|
||||
"verticalTop": ".t--button-group-TOP",
|
||||
"verticalCenter": ".t--button-group-CENTER",
|
||||
"verticalBottom": ".t--button-group-BOTTOM",
|
||||
"textColor": ".t--property-control-textcolor input",
|
||||
"boadercolorPicker": ".t--property-control-bordercolour input",
|
||||
"boxShadowColorPicker": ".t--property-control-shadowcolor input",
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ const mySqlData = {
|
|||
["a", "abcdefghijklmnopqrst", "12345678912345", "true", "null"],
|
||||
["a", "abcdefghij", "012345", "false", "NulL"],
|
||||
["a", "b", "c"],
|
||||
["0", "1"],
|
||||
["false", "true"],
|
||||
[{"abc": "123"}, {}, [1, 2, 3, 4], [], ["a",true,0,12.34]],
|
||||
],
|
||||
query: {
|
||||
|
|
|
|||
|
|
@ -579,8 +579,8 @@ export class AggregateHelper {
|
|||
cy.get(selector)
|
||||
.contains(containsText)
|
||||
.eq(index)
|
||||
.click()
|
||||
.wait(200);
|
||||
.click({ force: true })
|
||||
.wait(500);
|
||||
}
|
||||
|
||||
public CheckUncheck(selector: string, check = true) {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,22 @@ export class DataSources {
|
|||
private _queryTimeout =
|
||||
"//input[@name='actionConfiguration.timeoutInMillisecond']";
|
||||
_getStructureReq = "/api/v1/datasources/*/structure?ignoreCache=true";
|
||||
_editDatasourceFromActiveTab = (dsName: string) =>
|
||||
".t--datasource-name:contains('" + dsName + "')";
|
||||
private _urlInputControl = "input[name='url']";
|
||||
|
||||
// Authenticated API locators
|
||||
private _authType = "[data-cy=authType]";
|
||||
private _oauth2 = ".t--dropdown-option:contains('OAuth 2.0')";
|
||||
private _accessTokenUrl = "[data-cy='authentication.accessTokenUrl'] input";
|
||||
private _clientID = "[data-cy='authentication.clientId'] input";
|
||||
private _clientSecret = "[data-cy='authentication.clientSecret'] input";
|
||||
private _authorizationCode =
|
||||
".t--dropdown-option:contains('Authorization Code')";
|
||||
private _grantType = "[data-cy='authentication.grantType']";
|
||||
private _authorizationURL =
|
||||
"[data-cy='authentication.authorizationUrl'] input";
|
||||
|
||||
public _datasourceModalSave = ".t--datasource-modal-save";
|
||||
public _datasourceModalDoNotSave = ".t--datasource-modal-do-not-save";
|
||||
|
||||
|
|
@ -372,7 +388,9 @@ export class DataSources {
|
|||
public TestDatasource(expectedRes = true) {
|
||||
this.agHelper.GetNClick(this._testDs, 0, false, 0);
|
||||
this.agHelper.ValidateNetworkDataSuccess("@testDatasource", expectedRes);
|
||||
this.agHelper.AssertContains("datasource is valid");
|
||||
if (expectedRes) {
|
||||
this.agHelper.AssertContains("datasource is valid");
|
||||
}
|
||||
}
|
||||
|
||||
public SaveDatasource() {
|
||||
|
|
@ -391,7 +409,7 @@ export class DataSources {
|
|||
this.agHelper.ValidateNetworkStatus("@saveDatasource", 201);
|
||||
}
|
||||
|
||||
public updateDatasource() {
|
||||
public UpdateDatasource() {
|
||||
this.agHelper.GetNClick(this._saveDs);
|
||||
// this.agHelper.ValidateNetworkStatus("@updateDatasource", 200);
|
||||
this.agHelper.AssertContains("datasource updated");
|
||||
|
|
@ -519,11 +537,11 @@ export class DataSources {
|
|||
}
|
||||
|
||||
public CloseReconnectDataSourceModal() {
|
||||
cy.get('body').then(($ele) =>{
|
||||
if($ele.find(this._reconnectDataSourceModal).length){
|
||||
this.agHelper.GetNClick(this._closeDataSourceModal)
|
||||
cy.get("body").then(($ele) => {
|
||||
if ($ele.find(this._reconnectDataSourceModal).length) {
|
||||
this.agHelper.GetNClick(this._closeDataSourceModal);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
RunQuery(
|
||||
|
|
@ -760,7 +778,7 @@ export class DataSources {
|
|||
) {
|
||||
cy.intercept("GET", this._getStructureReq).as("getDSStructure");
|
||||
if (isUpdate) {
|
||||
this.updateDatasource();
|
||||
this.UpdateDatasource();
|
||||
} else {
|
||||
this.SaveDatasource();
|
||||
}
|
||||
|
|
@ -772,6 +790,8 @@ export class DataSources {
|
|||
|
||||
public SaveDSFromDialog(save = true) {
|
||||
this.agHelper.GoBack();
|
||||
this.agHelper.AssertElementVisible(this._datasourceModalDoNotSave);
|
||||
this.agHelper.AssertElementVisible(this._datasourceModalSave);
|
||||
if (save) {
|
||||
this.agHelper.GetNClick(
|
||||
this.locator._visibleTextSpan("SAVE"),
|
||||
|
|
@ -790,7 +810,40 @@ export class DataSources {
|
|||
);
|
||||
}
|
||||
|
||||
public getDSEntity(dSName: string){
|
||||
public getDSEntity(dSName: string) {
|
||||
return `[data-guided-tour-id="explorer-entity-${dSName}"]`;
|
||||
}
|
||||
|
||||
public FillAuthAPIUrl() {
|
||||
const URL = datasourceFormData["authenticatedApiUrl"];
|
||||
this.agHelper.TypeText(this._urlInputControl, URL);
|
||||
}
|
||||
|
||||
public AddOAuth2AuthorizationCodeDetails(
|
||||
accessTokenUrl: string,
|
||||
clientId: string,
|
||||
clientSecret: string,
|
||||
authURL: string,
|
||||
) {
|
||||
this.agHelper.GetNClick(this._authType);
|
||||
this.agHelper.GetNClick(this._oauth2);
|
||||
this.agHelper.GetNClick(this._grantType);
|
||||
this.agHelper.GetNClick(this._authorizationCode);
|
||||
this.agHelper.TypeText(this._accessTokenUrl, accessTokenUrl);
|
||||
this.agHelper.TypeText(this._clientID, clientId);
|
||||
this.agHelper.TypeText(this._clientSecret, clientSecret);
|
||||
this.agHelper.TypeText(this._authorizationURL, authURL);
|
||||
}
|
||||
|
||||
public EditDSFromActiveTab(dsName: string) {
|
||||
this.agHelper.GetNClick(this._editDatasourceFromActiveTab(dsName));
|
||||
}
|
||||
|
||||
public FillMongoDatasourceFormWithURI(uri: string) {
|
||||
this.ValidateNSelectDropdown("Use Mongo Connection String URI", "", "Yes");
|
||||
this.agHelper.TypeText(
|
||||
this.locator._inputFieldByName("Connection String URI") + "//input",
|
||||
uri,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,16 @@ export class HomePage {
|
|||
private _deleteAppConfirm = '[data-cy="t--delete"]';
|
||||
private _wsAction = (action: string) =>
|
||||
"//span[text()='" + action + "']/ancestor::a";
|
||||
private _homeTab = ".t--apps-tab";
|
||||
private _templatesTab = ".t--templates-tab";
|
||||
|
||||
public SwitchToAppsTab() {
|
||||
this.agHelper.GetNClick(this._homeTab);
|
||||
}
|
||||
|
||||
public SwitchToTemplatesTab() {
|
||||
this.agHelper.GetNClick(this._templatesTab);
|
||||
}
|
||||
|
||||
public CreateNewWorkspace(workspaceNewName: string) {
|
||||
let oldName = "";
|
||||
|
|
|
|||
|
|
@ -1673,7 +1673,7 @@ Cypress.Commands.add("checkLabelForWidget", (options) => {
|
|||
const containerSelector = `${widgetSelector} ${options.containerSelector}`;
|
||||
const labelPositionSelector = ".t--property-control-position";
|
||||
const labelAlignmentRightSelector =
|
||||
".t--property-control-alignment .t--button-tab-right";
|
||||
".t--property-control-alignment .t--button-group-right";
|
||||
const labelWidth = options.labelWidth;
|
||||
|
||||
// Drag a widget
|
||||
|
|
@ -1690,17 +1690,17 @@ Cypress.Commands.add("checkLabelForWidget", (options) => {
|
|||
.contains(labelText);
|
||||
|
||||
// Set the label position: Auto
|
||||
cy.get(".t--button-tab-Auto").click({ force: true });
|
||||
cy.get(".t--button-group-Auto").click({ force: true });
|
||||
// Assert label position: Auto
|
||||
cy.get(containerSelector).should("have.css", "flex-direction", "column");
|
||||
|
||||
// Change the label position to Top
|
||||
cy.get(".t--button-tab-Top").click({ force: true });
|
||||
cy.get(".t--button-group-Top").click({ force: true });
|
||||
// Assert label position: Top
|
||||
cy.get(containerSelector).should("have.css", "flex-direction", "column");
|
||||
|
||||
// Change the label position to Left
|
||||
cy.get(".t--button-tab-Left").click({ force: true });
|
||||
cy.get(".t--button-group-Left").click({ force: true });
|
||||
// Assert label position: Left
|
||||
cy.get(containerSelector).should("have.css", "flex-direction", "row");
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
"cypress-log-to-output": "^1.1.2",
|
||||
"dayjs": "^1.10.6",
|
||||
"deep-diff": "^1.0.2",
|
||||
"design-system": "npm:@appsmithorg/design-system@1.0.41",
|
||||
"design-system": "npm:@appsmithorg/design-system@1.0.44",
|
||||
"downloadjs": "^1.4.7",
|
||||
"draft-js": "^0.11.7",
|
||||
"exceljs-lightweight": "^1.14.0",
|
||||
|
|
|
|||
|
|
@ -338,6 +338,25 @@ export const toggleSaveActionFromPopupFlag = (isDSSavedFromPopup: boolean) => {
|
|||
};
|
||||
};
|
||||
|
||||
// This function stores the config property for key value pairs in
|
||||
// datasource form which are initialized by default
|
||||
export const setDefaultKeyValPairFlag = (defaultKeyValArrayConfig: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET,
|
||||
payload: defaultKeyValArrayConfig,
|
||||
};
|
||||
};
|
||||
|
||||
// This function resets the config property stored in redux for key value pairs in
|
||||
// datasource form which are initialized by default, once these key value pairs are initialized
|
||||
// in the datasource config form, store needs to reset those values
|
||||
export const resetDefaultKeyValPairFlag = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.RESET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET,
|
||||
payload: [],
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
fetchDatasources,
|
||||
initDatasourcePane,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export const EVALUATE_REDUX_ACTIONS = [
|
|||
ReduxActionTypes.FETCH_JS_ACTIONS_VIEW_MODE_SUCCESS,
|
||||
ReduxActionErrorTypes.FETCH_JS_ACTIONS_VIEW_MODE_ERROR,
|
||||
ReduxActionTypes.UPDATE_JS_ACTION_BODY_SUCCESS,
|
||||
ReduxActionTypes.EXECUTE_JS_FUNCTION_SUCCESS,
|
||||
ReduxActionTypes.SET_JS_FUNCTION_EXECUTION_DATA,
|
||||
// App Data
|
||||
ReduxActionTypes.SET_APP_MODE,
|
||||
ReduxActionTypes.FETCH_USER_DETAILS_SUCCESS,
|
||||
|
|
|
|||
|
|
@ -557,6 +557,7 @@ export const ReduxActionTypes = {
|
|||
FETCH_JS_ACTIONS_VIEW_MODE_SUCCESS: "FETCH_JS_ACTIONS_VIEW_MODE_SUCCESS",
|
||||
EXECUTE_JS_FUNCTION_INIT: "EXECUTE_JS_FUNCTION_INIT",
|
||||
EXECUTE_JS_FUNCTION_SUCCESS: "EXECUTE_JS_FUNCTION_SUCCESS",
|
||||
SET_JS_FUNCTION_EXECUTION_DATA: "SET_JS_FUNCTION_EXECUTION_DATA",
|
||||
GET_PLUGIN_FORM_CONFIG_INIT: "GET_PLUGIN_FORM_CONFIG_INIT",
|
||||
EXECUTE_DATASOURCE_QUERY_INIT: "EXECUTE_DATASOURCE_QUERY_INIT",
|
||||
EXECUTE_DATASOURCE_QUERY_SUCCESS: "EXECUTE_DATASOURCE_QUERY_SUCCESS",
|
||||
|
|
@ -752,6 +753,10 @@ export const ReduxActionTypes = {
|
|||
SET_DATASOURCE_SAVE_ACTION_FLAG: "SET_DATASOURCE_SAVE_ACTION_FLAG",
|
||||
SET_DATASOURCE_SAVE_ACTION_FROM_POPUP_FLAG:
|
||||
"SET_DATASOURCE_SAVE_ACTION_FROM_POPUP_FLAG",
|
||||
SET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET:
|
||||
"SET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET",
|
||||
RESET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET:
|
||||
"RESET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET",
|
||||
};
|
||||
|
||||
export type ReduxActionType = typeof ReduxActionTypes[keyof typeof ReduxActionTypes];
|
||||
|
|
|
|||
|
|
@ -1190,6 +1190,8 @@ export const ADMIN_BRANDING_COLOR_TOOLTIP_FONT = () =>
|
|||
`Used as text color for the buttons.`;
|
||||
export const ADMIN_BRANDING_COLOR_TOOLTIP_DISABLED = () =>
|
||||
`Used as background color for disabled buttons.`;
|
||||
export const ADMIN_BRANDING_UPGRADE_INTERCOM_MESSAGE = () =>
|
||||
`I would like to enable Custom Branding for my workspace and am interested in Appsmith Business.`;
|
||||
|
||||
// Guided tour
|
||||
// -- STEPS ---
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ export function AuthPage({ authMethods }: { authMethods: AuthMethodType[] }) {
|
|||
</MethodDetailsWrapper>
|
||||
<StyledAuthButton
|
||||
category={
|
||||
method.isConnected ? Category.primary : Category.tertiary
|
||||
method.isConnected ? Category.primary : Category.secondary
|
||||
}
|
||||
className={`t--settings-sub-category-${
|
||||
method.needsUpgrade
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Button } from "design-system";
|
|||
import {
|
||||
ADMIN_BRANDING_SETTINGS_SUBTITLE,
|
||||
ADMIN_BRANDING_SETTINGS_TITLE,
|
||||
ADMIN_BRANDING_UPGRADE_INTERCOM_MESSAGE,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import useOnUpgrade from "utils/hooks/useOnUpgrade";
|
||||
|
|
@ -15,8 +16,7 @@ import {
|
|||
const UpgradeBanner = () => {
|
||||
const { onUpgrade } = useOnUpgrade({
|
||||
logEventName: "BRANDING_UPGRADE_CLICK",
|
||||
intercomMessage:
|
||||
"Hello, I would like to upgrade my appsmith instance to use the custom branding feature",
|
||||
intercomMessage: createMessage(ADMIN_BRANDING_UPGRADE_INTERCOM_MESSAGE),
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -636,6 +636,7 @@ export default connect(
|
|||
applicationId?: string;
|
||||
workspaceId?: string;
|
||||
isApplicationInvite?: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
>({
|
||||
validate,
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ const StyledButton = styled((props) => (
|
|||
} !important;
|
||||
}
|
||||
|
||||
&:hover:enabled, &:active:enabled {
|
||||
&:hover:enabled, &:active:enabled. &:focus:enabled {
|
||||
background: ${
|
||||
buttonStyle === ButtonStyleTypes.WARNING
|
||||
? buttonVariant === ButtonVariantTypes.SECONDARY
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ import {
|
|||
import { POSITIONED_WIDGET } from "constants/componentClassNameConstants";
|
||||
import equal from "fast-deep-equal";
|
||||
|
||||
const PositionedWidget = styled.div<{ zIndexOnHover: number }>`
|
||||
const PositionedWidget = styled.div<{
|
||||
zIndexOnHover: number;
|
||||
disabled?: boolean;
|
||||
}>`
|
||||
&:hover {
|
||||
z-index: ${(props) => props.zIndexOnHover} !important;
|
||||
}
|
||||
|
|
@ -42,6 +45,8 @@ export type PositionedContainerProps = {
|
|||
noContainerOffset?: boolean;
|
||||
leftColumn: number;
|
||||
parentColumnSpace: number;
|
||||
isDisabled?: boolean;
|
||||
isVisible?: boolean;
|
||||
};
|
||||
|
||||
export const checkIsDropTarget = memoize(function isDropTarget(
|
||||
|
|
@ -163,7 +168,9 @@ export function PositionedContainer(props: PositionedContainerProps) {
|
|||
return (
|
||||
<PositionedWidget
|
||||
className={containerClassName}
|
||||
data-hidden={!props.isVisible || undefined}
|
||||
data-testid="test-widget"
|
||||
disabled={props.isDisabled}
|
||||
id={props.widgetId}
|
||||
key={`positioned-container-${props.widgetId}`}
|
||||
// Positioned Widget is the top enclosure for all widgets and clicks on/inside the widget should not be propagated/bubbled out of this Container.
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ const addMarksForChildren = (
|
|||
tokenEnd: number,
|
||||
editor: CodeMirror.Editor,
|
||||
) => {
|
||||
const childNodes = navigationData.children;
|
||||
const childNodes = navigationData.children || {};
|
||||
if (Object.keys(childNodes).length) {
|
||||
const token = editor.getTokenAt(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import {
|
|||
TextInputProps,
|
||||
TextType,
|
||||
} from "design-system";
|
||||
import { setDefaultKeyValPairFlag } from "actions/datasourceActions";
|
||||
import { useDispatch } from "react-redux";
|
||||
export interface KeyValueArrayControlProps extends ControlProps {
|
||||
name: string;
|
||||
label: string;
|
||||
|
|
@ -88,6 +90,7 @@ function KeyValueRow(
|
|||
const keyName = getFieldName(extraData[0]?.configProperty);
|
||||
const valueName = getFieldName(extraData[1]?.configProperty);
|
||||
const keyFieldProps = extraData[0];
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const addRow = useCallback(() => {
|
||||
if (keyName && valueName) {
|
||||
|
|
@ -102,6 +105,9 @@ function KeyValueRow(
|
|||
if (props.fields.length < 1) {
|
||||
for (let i = props.fields.length; i < 1; i += 1) {
|
||||
addRow();
|
||||
// Since we are initializing one default key value pair, it needs to stored in redux store
|
||||
// so that it can be used to initilize datasource config form as well
|
||||
dispatch(setDefaultKeyValPairFlag(props.configProperty));
|
||||
}
|
||||
}
|
||||
}, [props.fields, keyName, valueName]);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { TooltipComponent } from "design-system";
|
||||
import { ButtonGroup, TooltipComponent } from "design-system";
|
||||
import BaseControl, { ControlData, ControlProps } from "./BaseControl";
|
||||
import { borderRadiusOptions } from "constants/ThemeConstants";
|
||||
import { ButtonTab } from "design-system";
|
||||
import {
|
||||
DSEventDetail,
|
||||
DSEventTypes,
|
||||
|
|
@ -64,7 +63,7 @@ class BorderRadiusOptionsControl extends BaseControl<
|
|||
|
||||
handleAdsEvent = (e: CustomEvent<DSEventDetail>) => {
|
||||
if (
|
||||
e.detail.component === "ButtonTab" &&
|
||||
e.detail.component === "ButtonGroup" &&
|
||||
e.detail.event === DSEventTypes.KEYPRESS
|
||||
) {
|
||||
emitInteractionAnalyticsEvent(this.componentRef.current, {
|
||||
|
|
@ -80,7 +79,7 @@ class BorderRadiusOptionsControl extends BaseControl<
|
|||
|
||||
public render() {
|
||||
return (
|
||||
<ButtonTab
|
||||
<ButtonGroup
|
||||
options={options}
|
||||
ref={this.componentRef}
|
||||
selectButton={(value, isUpdatedViaKeyboard = false) => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import * as React from "react";
|
||||
|
||||
import BaseControl, { ControlData, ControlProps } from "./BaseControl";
|
||||
import { TooltipComponent } from "design-system";
|
||||
import { ButtonGroup, TooltipComponent } from "design-system";
|
||||
import { boxShadowOptions } from "constants/ThemeConstants";
|
||||
import CloseLineIcon from "remixicon-react/CloseLineIcon";
|
||||
import { ButtonTab } from "design-system";
|
||||
import {
|
||||
DSEventDetail,
|
||||
DSEventTypes,
|
||||
|
|
@ -58,7 +57,7 @@ class BoxShadowOptionsControl extends BaseControl<
|
|||
|
||||
handleAdsEvent = (e: CustomEvent<DSEventDetail>) => {
|
||||
if (
|
||||
e.detail.component === "ButtonTab" &&
|
||||
e.detail.component === "ButtonGroup" &&
|
||||
e.detail.event === DSEventTypes.KEYPRESS
|
||||
) {
|
||||
emitInteractionAnalyticsEvent(this.componentRef.current, {
|
||||
|
|
@ -74,7 +73,7 @@ class BoxShadowOptionsControl extends BaseControl<
|
|||
|
||||
public render() {
|
||||
return (
|
||||
<ButtonTab
|
||||
<ButtonGroup
|
||||
options={options}
|
||||
ref={this.componentRef}
|
||||
selectButton={(value, isUpdatedViaKeyboard = false) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import BaseControl, { ControlData, ControlProps } from "./BaseControl";
|
||||
import { ButtonTab, ButtonTabOption } from "design-system";
|
||||
import { ButtonGroup, ButtonGroupOption } from "design-system";
|
||||
import produce from "immer";
|
||||
import {
|
||||
DSEventDetail,
|
||||
|
|
@ -28,7 +28,7 @@ class ButtonTabControl extends BaseControl<ButtonTabControlProps> {
|
|||
|
||||
handleAdsEvent = (e: CustomEvent<DSEventDetail>) => {
|
||||
if (
|
||||
e.detail.component === "ButtonTab" &&
|
||||
e.detail.component === "ButtonGroup" &&
|
||||
e.detail.event === DSEventTypes.KEYPRESS
|
||||
) {
|
||||
emitInteractionAnalyticsEvent(this.componentRef.current, {
|
||||
|
|
@ -67,7 +67,7 @@ class ButtonTabControl extends BaseControl<ButtonTabControlProps> {
|
|||
render() {
|
||||
const { options, propertyValue } = this.props;
|
||||
return (
|
||||
<ButtonTab
|
||||
<ButtonGroup
|
||||
options={options}
|
||||
ref={this.componentRef}
|
||||
selectButton={this.selectButton}
|
||||
|
|
@ -77,7 +77,7 @@ class ButtonTabControl extends BaseControl<ButtonTabControlProps> {
|
|||
}
|
||||
|
||||
static getControlType() {
|
||||
return "BUTTON_TABS";
|
||||
return "BUTTON_GROUP";
|
||||
}
|
||||
|
||||
static canDisplayValueInUI(config: ControlData, value: any): boolean {
|
||||
|
|
@ -98,7 +98,7 @@ class ButtonTabControl extends BaseControl<ButtonTabControlProps> {
|
|||
}
|
||||
|
||||
export interface ButtonTabControlProps extends ControlProps {
|
||||
options: ButtonTabOption[];
|
||||
options: ButtonGroupOption[];
|
||||
defaultValue: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import BaseControl, { ControlData, ControlProps } from "./BaseControl";
|
||||
import { ButtonTab, ButtonTabOption } from "design-system";
|
||||
import { ButtonGroup, ButtonGroupOption } from "design-system";
|
||||
import {
|
||||
DSEventDetail,
|
||||
DSEventTypes,
|
||||
|
|
@ -27,7 +27,7 @@ class IconTabControl extends BaseControl<IconTabControlProps> {
|
|||
|
||||
handleAdsEvent = (e: CustomEvent<DSEventDetail>) => {
|
||||
if (
|
||||
e.detail.component === "ButtonTab" &&
|
||||
e.detail.component === "ButtonGroup" &&
|
||||
e.detail.event === DSEventTypes.KEYPRESS
|
||||
) {
|
||||
emitInteractionAnalyticsEvent(this.componentRef.current, {
|
||||
|
|
@ -52,7 +52,7 @@ class IconTabControl extends BaseControl<IconTabControlProps> {
|
|||
render() {
|
||||
const { fullWidth, options, propertyValue } = this.props;
|
||||
return (
|
||||
<ButtonTab
|
||||
<ButtonGroup
|
||||
fullWidth={fullWidth}
|
||||
options={options}
|
||||
ref={this.componentRef}
|
||||
|
|
@ -78,7 +78,7 @@ class IconTabControl extends BaseControl<IconTabControlProps> {
|
|||
}
|
||||
|
||||
export interface IconTabControlProps extends ControlProps {
|
||||
options: ButtonTabOption[];
|
||||
options: ButtonGroupOption[];
|
||||
defaultValue: string;
|
||||
fullWidth: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import styled from "styled-components";
|
|||
import { Alignment } from "@blueprintjs/core";
|
||||
|
||||
import BaseControl, { ControlProps } from "./BaseControl";
|
||||
import { ButtonTab, ButtonTabOption } from "design-system";
|
||||
import { ButtonGroup, ButtonGroupOption } from "design-system";
|
||||
import {
|
||||
DSEventDetail,
|
||||
DSEventTypes,
|
||||
|
|
@ -22,7 +22,7 @@ const ControlContainer = styled.div`
|
|||
|
||||
export interface LabelAlignmentOptionsControlProps extends ControlProps {
|
||||
propertyValue?: Alignment;
|
||||
options: ButtonTabOption[];
|
||||
options: ButtonGroupOption[];
|
||||
defaultValue: Alignment;
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ class LabelAlignmentOptionsControl extends BaseControl<
|
|||
|
||||
handleAdsEvent = (e: CustomEvent<DSEventDetail>) => {
|
||||
if (
|
||||
e.detail.component === "ButtonTab" &&
|
||||
e.detail.component === "ButtonGroup" &&
|
||||
e.detail.event === DSEventTypes.KEYPRESS
|
||||
) {
|
||||
emitInteractionAnalyticsEvent(this.componentRef.current, {
|
||||
|
|
@ -70,7 +70,7 @@ class LabelAlignmentOptionsControl extends BaseControl<
|
|||
const { options, propertyValue } = this.props;
|
||||
return (
|
||||
<ControlContainer>
|
||||
<ButtonTab
|
||||
<ButtonGroup
|
||||
options={options}
|
||||
ref={this.componentRef}
|
||||
selectButton={this.handleAlign}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import {
|
|||
stringToJS,
|
||||
} from "components/editorComponents/ActionCreator/utils";
|
||||
import { AdditionalDynamicDataTree } from "utils/autocomplete/customTreeTypeDefCreator";
|
||||
import { ColumnProperties } from "widgets/TableWidgetV2/component/Constants";
|
||||
import { getUniqueKeysFromSourceData } from "widgets/MenuButtonWidget/widget/helper";
|
||||
|
||||
const PromptMessage = styled.span`
|
||||
line-height: 17px;
|
||||
|
|
@ -93,18 +95,34 @@ class MenuButtonDynamicItemsControl extends BaseControl<
|
|||
label,
|
||||
propertyValue,
|
||||
theme,
|
||||
widgetProperties,
|
||||
} = this.props;
|
||||
const menuButtonId = this.props.widgetProperties.widgetName;
|
||||
const widgetName = widgetProperties.widgetName;
|
||||
const widgetType = widgetProperties.type;
|
||||
const value =
|
||||
propertyValue && isDynamicValue(propertyValue)
|
||||
? MenuButtonDynamicItemsControl.getInputComputedValue(
|
||||
propertyValue,
|
||||
menuButtonId,
|
||||
widgetName,
|
||||
widgetType,
|
||||
widgetProperties.primaryColumns,
|
||||
)
|
||||
: propertyValue
|
||||
? propertyValue
|
||||
: defaultValue;
|
||||
const keys = this.props.widgetProperties.sourceDataKeys || [];
|
||||
let sourceData;
|
||||
|
||||
if (widgetType === "TABLE_WIDGET_V2") {
|
||||
sourceData =
|
||||
widgetProperties?.__evaluation__?.evaluatedValues?.primaryColumns?.[
|
||||
`${Object.keys(widgetProperties.primaryColumns)[0]}`
|
||||
]?.sourceData;
|
||||
} else if (widgetType === "MENU_BUTTON_WIDGET") {
|
||||
sourceData =
|
||||
widgetProperties?.__evaluation__?.evaluatedValues?.sourceData;
|
||||
}
|
||||
|
||||
const keys = getUniqueKeysFromSourceData(sourceData);
|
||||
const currentItem: { [key: string]: any } = {};
|
||||
|
||||
Object.values(keys).forEach((key) => {
|
||||
|
|
@ -115,6 +133,7 @@ class MenuButtonDynamicItemsControl extends BaseControl<
|
|||
if (value && !propertyValue) {
|
||||
this.onTextChange(value);
|
||||
}
|
||||
|
||||
return (
|
||||
<InputText
|
||||
additionalDynamicData={{
|
||||
|
|
@ -131,30 +150,61 @@ class MenuButtonDynamicItemsControl extends BaseControl<
|
|||
);
|
||||
}
|
||||
|
||||
static getBindingPrefix = (menuButtonId: string) => {
|
||||
return `{{${menuButtonId}.sourceData.map((currentItem, currentIndex) => ( `;
|
||||
static getBindingPrefix = (
|
||||
widgetName: string,
|
||||
widgetType?: string,
|
||||
primaryColumns?: Record<string, ColumnProperties>,
|
||||
) => {
|
||||
if (widgetType === "TABLE_WIDGET_V2" && primaryColumns) {
|
||||
const columnName = Object.keys(primaryColumns)?.[0];
|
||||
|
||||
return `{{${widgetName}.processedTableData.map((currentRow, currentRowIndex) => {
|
||||
let primaryColumnData = [];
|
||||
|
||||
if (${widgetName}.primaryColumns.${columnName}.sourceData[currentRowIndex].length) {
|
||||
primaryColumnData = ${widgetName}.primaryColumns.${columnName}.sourceData[currentRowIndex];
|
||||
} else if (${widgetName}.primaryColumns.${columnName}.sourceData.length) {
|
||||
primaryColumnData = ${widgetName}.primaryColumns.${columnName}.sourceData;
|
||||
}
|
||||
|
||||
return primaryColumnData.map((currentItem, currentIndex) => `;
|
||||
} else {
|
||||
return `{{${widgetName}.sourceData.map((currentItem, currentIndex) => ( `;
|
||||
}
|
||||
};
|
||||
|
||||
static bindingSuffix = `))}}`;
|
||||
static getBindingSuffix = (widgetType?: string) =>
|
||||
widgetType === "TABLE_WIDGET_V2" ? `);});}}` : `))}}`;
|
||||
|
||||
static getInputComputedValue = (
|
||||
propertyValue: string,
|
||||
menuButtonId: string,
|
||||
widgetName: string,
|
||||
widgetType?: string,
|
||||
primaryColumns?: Record<string, ColumnProperties>,
|
||||
) => {
|
||||
if (!propertyValue.includes(this.getBindingPrefix(menuButtonId))) {
|
||||
if (
|
||||
!propertyValue.includes(
|
||||
this.getBindingPrefix(widgetName, widgetType, primaryColumns),
|
||||
)
|
||||
) {
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
const value = `${propertyValue.substring(
|
||||
this.getBindingPrefix(menuButtonId).length,
|
||||
propertyValue.length - this.bindingSuffix.length,
|
||||
this.getBindingPrefix(widgetName, widgetType, primaryColumns).length,
|
||||
propertyValue.length - this.getBindingSuffix(widgetType).length,
|
||||
)}`;
|
||||
const stringValue = JSToString(value);
|
||||
|
||||
return stringValue;
|
||||
};
|
||||
|
||||
getComputedValue = (value: string, menuButtonId: string) => {
|
||||
getComputedValue = (
|
||||
value: string,
|
||||
widgetName: string,
|
||||
widgetType?: string,
|
||||
primaryColumns?: Record<string, ColumnProperties>,
|
||||
) => {
|
||||
if (!isDynamicValue(value)) {
|
||||
return value;
|
||||
}
|
||||
|
|
@ -166,8 +216,12 @@ class MenuButtonDynamicItemsControl extends BaseControl<
|
|||
}
|
||||
|
||||
return `${MenuButtonDynamicItemsControl.getBindingPrefix(
|
||||
menuButtonId,
|
||||
)}${stringToEvaluate}${MenuButtonDynamicItemsControl.bindingSuffix}`;
|
||||
widgetName,
|
||||
widgetType,
|
||||
primaryColumns,
|
||||
)}${stringToEvaluate}${MenuButtonDynamicItemsControl.getBindingSuffix(
|
||||
widgetType,
|
||||
)}`;
|
||||
};
|
||||
|
||||
onTextChange = (event: React.ChangeEvent<HTMLTextAreaElement> | string) => {
|
||||
|
|
@ -181,6 +235,8 @@ class MenuButtonDynamicItemsControl extends BaseControl<
|
|||
const output = this.getComputedValue(
|
||||
value,
|
||||
this.props.widgetProperties.widgetName,
|
||||
this.props.widgetProperties.type,
|
||||
this.props.widgetProperties.primaryColumns,
|
||||
);
|
||||
|
||||
this.updateProperty(this.props.propertyName, output);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class OpenConfigPanelControl extends BaseControl<OpenConfigPanelControlProps> {
|
|||
<Wrapper>
|
||||
<StyledPropertyPaneButtonWrapper>
|
||||
<OpenNextPannelButton
|
||||
category={Category.tertiary}
|
||||
category={Category.secondary}
|
||||
className={`t--${widgetName}-open-next-panel-button`}
|
||||
icon={icon}
|
||||
iconPosition="right"
|
||||
|
|
|
|||
|
|
@ -177,11 +177,13 @@ class ComputeTablePropertyControlV2 extends BaseControl<
|
|||
|
||||
onTextChange = (event: React.ChangeEvent<HTMLTextAreaElement> | string) => {
|
||||
let value = "";
|
||||
|
||||
if (typeof event !== "string") {
|
||||
value = event.target?.value;
|
||||
} else {
|
||||
value = event;
|
||||
}
|
||||
|
||||
if (isString(value)) {
|
||||
const output = this.getComputedValue(
|
||||
value,
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ const Checkbox = styled(BlueprintCheckbox)<StyledCheckboxProps>`
|
|||
}
|
||||
|
||||
// hover
|
||||
&.bp3-control.bp3-checkbox:hover input:not(:checked) ~ .bp3-control-indicator {
|
||||
&.bp3-control.bp3-checkbox:hover input:not(:checked) ~ .bp3-control-indicator,
|
||||
input:not(:checked):focus ~ .bp3-control-indicator {
|
||||
box-shadow: 0px 0px 0px 1px ${
|
||||
hasError
|
||||
? "var(--wds-color-border-danger-hover)"
|
||||
|
|
@ -68,7 +69,10 @@ const Checkbox = styled(BlueprintCheckbox)<StyledCheckboxProps>`
|
|||
}
|
||||
|
||||
// hover on checked
|
||||
&.bp3-control.bp3-checkbox:hover input:checked ~ .bp3-control-indicator, &.bp3-control.bp3-checkbox:hover input:indeterminate ~ .bp3-control-indicator {
|
||||
&.bp3-control.bp3-checkbox:hover input:checked ~ .bp3-control-indicator,
|
||||
&.bp3-control.bp3-checkbox:hover input:indeterminate ~ .bp3-control-indicator,
|
||||
&.bp3-control.bp3-checkbox input:checked:focus ~ .bp3-control-indicator,
|
||||
&.bp3-control.bp3-checkbox input:indeterminate:focus ~ .bp3-control-indicator {
|
||||
box-shadow: none;
|
||||
background: ${darkenColor(accentColor)} !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,10 +105,9 @@ export const BlueprintControlTransform = css`
|
|||
border: 1px solid var(--wds-color-border-disabled) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
& input:not(:checked):not(:disabled) ~ .bp3-control-indicator {
|
||||
border: 1px solid ${Colors.GREY_6} !important;
|
||||
}
|
||||
&:hover input:not(:checked):not(:disabled) ~ .bp3-control-indicator,
|
||||
& input:not(:checked):not(:disabled):focus ~ .bp3-control-indicator {
|
||||
border: 1px solid var(--wds-color-bg-disabled-strong) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,11 +136,10 @@ export const BlueprintControlTransform = css`
|
|||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
& input:not(:checked):not(:disabled) ~ .bp3-control-indicator {
|
||||
background: var(--wds-color-bg-strong-hover);
|
||||
border: 1px solid var(--wds-color-border-hover) !important;
|
||||
}
|
||||
&:hover input:not(:checked):not(:disabled) ~ .bp3-control-indicator,
|
||||
input:not(:checked):not(:disabled):focus ~ .bp3-control-indicator {
|
||||
background: var(--wds-color-bg-strong-hover);
|
||||
border: 1px solid var(--wds-color-border-hover) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const layoutConfigurations: LayoutConfigurations = {
|
|||
FLUID: { minWidth: -1, maxWidth: -1 },
|
||||
};
|
||||
|
||||
export const LATEST_PAGE_VERSION = 74;
|
||||
export const LATEST_PAGE_VERSION = 75;
|
||||
|
||||
export const GridDefaults = {
|
||||
DEFAULT_CELL_SIZE: 1,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
export function getStickyCanvasName(widgetId: string) {
|
||||
export function getSlidingArenaName(widgetId: string) {
|
||||
return `div-selection-${widgetId}`;
|
||||
}
|
||||
|
||||
export function getSlidingCanvasName(widgetId: string) {
|
||||
export function getStickyCanvasName(widgetId: string) {
|
||||
return `canvas-selection-${widgetId}`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export interface Oauth2Common {
|
|||
isAuthorizationHeader: boolean;
|
||||
audience: string;
|
||||
resource: string;
|
||||
sendScopeWithRefreshToken: string;
|
||||
sendScopeWithRefreshToken: boolean;
|
||||
refreshTokenClientCredentialsLocation: string;
|
||||
useSelfSignedCert?: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import {
|
|||
checkContainersForAutoHeightAction,
|
||||
updateWidgetAutoHeightAction,
|
||||
} from "actions/autoHeightActions";
|
||||
import useWidgetFocus from "utils/hooks/useWidgetFocus/useWidgetFocus";
|
||||
|
||||
const AppViewerBody = styled.section<{
|
||||
hasPages: boolean;
|
||||
|
|
@ -96,6 +97,8 @@ function AppViewer(props: Props) {
|
|||
const prevValues = usePrevious({ branch, location: props.location, pageId });
|
||||
const { hideWatermark } = getAppsmithConfigs();
|
||||
|
||||
const focusRef = useWidgetFocus();
|
||||
|
||||
/**
|
||||
* initializes the widgets factory and registers all widgets
|
||||
*/
|
||||
|
|
@ -268,6 +271,7 @@ function AppViewer(props: Props) {
|
|||
className={CANVAS_SELECTOR}
|
||||
hasPages={pages.length > 1}
|
||||
headerHeight={headerHeight}
|
||||
ref={focusRef}
|
||||
showGuidedTourMessage={showGuidedTourMessage}
|
||||
>
|
||||
{isInitialized && registered && <AppViewerPageContainer />}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ function ImportApplicationModal(props: ImportApplicationModalProps) {
|
|||
</FilePickerWrapper>
|
||||
<ButtonWrapper>
|
||||
<ImportButton
|
||||
// category={ButtonCategory.tertiary}
|
||||
// category={ButtonCategory.secondary}
|
||||
cypressSelector={"t--workspace-import-app-button"}
|
||||
disabled={!appFileToBeUploaded}
|
||||
isLoading={importingApplication}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { getCurrentGitBranch } from "selectors/gitSyncSelectors";
|
|||
import { getSelectedAppTheme } from "selectors/appThemingSelectors";
|
||||
import { getPageLevelSocketRoomId } from "sagas/WebsocketSagas/utils";
|
||||
import { previewModeSelector } from "selectors/editorSelectors";
|
||||
import useWidgetFocus from "utils/hooks/useWidgetFocus";
|
||||
|
||||
interface CanvasProps {
|
||||
widgetsStructure: CanvasWidgetStructure;
|
||||
|
|
@ -101,6 +102,8 @@ const Canvas = memo((props: CanvasProps) => {
|
|||
backgroundForCanvas = selectedTheme.properties.colors.backgroundColor;
|
||||
}
|
||||
|
||||
const focusRef = useWidgetFocus();
|
||||
|
||||
try {
|
||||
return (
|
||||
<Container
|
||||
|
|
@ -118,6 +121,7 @@ const Canvas = memo((props: CanvasProps) => {
|
|||
);
|
||||
!!data && delayedShareMousePointer(data);
|
||||
}}
|
||||
ref={focusRef}
|
||||
style={{
|
||||
width: canvasWidth,
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ function SaveOrDiscardDatasourceModal(props: SaveOrDiscardModalProps) {
|
|||
<div className="">
|
||||
<div className="flex items-center justify-end space-x-3">
|
||||
<Button
|
||||
category={Category.tertiary}
|
||||
category={Category.secondary}
|
||||
className="t--datasource-modal-do-not-save"
|
||||
onClick={onDiscard}
|
||||
size={Size.medium}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { getFormValues, isDirty } from "redux-form";
|
||||
import { getFormInitialValues, getFormValues, isDirty } from "redux-form";
|
||||
import { AppState } from "@appsmith/reducers";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
|
|
@ -16,6 +16,7 @@ import {
|
|||
toggleSaveActionFlag,
|
||||
toggleSaveActionFromPopupFlag,
|
||||
createTempDatasourceFromForm,
|
||||
resetDefaultKeyValPairFlag,
|
||||
} from "actions/datasourceActions";
|
||||
import {
|
||||
DATASOURCE_DB_FORM,
|
||||
|
|
@ -72,6 +73,9 @@ interface ReduxStateProps {
|
|||
triggerSave: boolean;
|
||||
isFormDirty: boolean;
|
||||
datasource: Datasource | undefined;
|
||||
defaultKeyValueArrayConfig: Array<string>;
|
||||
restAPIFormData: Datasource;
|
||||
initialValue: Datasource | undefined;
|
||||
}
|
||||
|
||||
interface DatasourcEditorProps {
|
||||
|
|
@ -204,25 +208,17 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
|||
const datasource = getDatasource(state, datasourceId);
|
||||
const { formConfigs } = plugins;
|
||||
const formData = getFormValues(DATASOURCE_DB_FORM)(state) as Datasource;
|
||||
const restAPIFormData = getFormValues(DATASOURCE_REST_API_FORM)(
|
||||
state,
|
||||
) as Datasource;
|
||||
const pluginId = _.get(datasource, "pluginId", "");
|
||||
const plugin = getPlugin(state, pluginId);
|
||||
const { applicationSlug, pageSlug } = selectURLSlugs(state);
|
||||
const formName =
|
||||
plugin?.type === "API" ? DATASOURCE_REST_API_FORM : DATASOURCE_DB_FORM;
|
||||
// for plugins, where 1 default endpoint is initialized,
|
||||
// added this check so that form isnt considered dirty with default endpoint
|
||||
const defaultEndpoints: Array<{
|
||||
host: string;
|
||||
port: string;
|
||||
}> = (formData?.datasourceConfiguration as any)?.endpoints || [];
|
||||
const isDefaultEndpoint =
|
||||
defaultEndpoints.length === 1 &&
|
||||
defaultEndpoints[0].host === "" &&
|
||||
defaultEndpoints[0].port === "";
|
||||
const isFormDirty =
|
||||
datasourceId === TEMP_DATASOURCE_ID
|
||||
? true
|
||||
: isDirty(formName)(state) && !isDefaultEndpoint;
|
||||
datasourceId === TEMP_DATASOURCE_ID ? true : isDirty(formName)(state);
|
||||
const initialValue = getFormInitialValues(formName)(state) as Datasource;
|
||||
|
||||
return {
|
||||
datasourceId,
|
||||
|
|
@ -248,6 +244,9 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
|||
triggerSave: datasources.isDatasourceBeingSavedFromPopup,
|
||||
isFormDirty,
|
||||
datasource,
|
||||
defaultKeyValueArrayConfig: datasourcePane.defaultKeyValueArrayConfig,
|
||||
restAPIFormData,
|
||||
initialValue,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -272,6 +271,7 @@ const mapDispatchToProps = (
|
|||
dispatch(toggleSaveActionFromPopupFlag(flag)),
|
||||
createTempDatasource: (data: any) =>
|
||||
dispatch(createTempDatasourceFromForm(data)),
|
||||
resetDefaultKeyValPairFlag: () => dispatch(resetDefaultKeyValPairFlag()),
|
||||
});
|
||||
|
||||
export interface DatasourcePaneFunctions {
|
||||
|
|
@ -283,6 +283,7 @@ export interface DatasourcePaneFunctions {
|
|||
toggleSaveActionFlag: (flag: boolean) => void;
|
||||
toggleSaveActionFromPopupFlag: (flag: boolean) => void;
|
||||
createTempDatasource: (data: any) => void;
|
||||
resetDefaultKeyValPairFlag: () => void;
|
||||
}
|
||||
|
||||
class DatasourceEditorRouter extends React.Component<Props, State> {
|
||||
|
|
@ -316,6 +317,7 @@ class DatasourceEditorRouter extends React.Component<Props, State> {
|
|||
this.closeDialogAndUnblockRoutes();
|
||||
}
|
||||
this.setViewModeFromQueryParams();
|
||||
this.initializeFormWithDefaults();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -370,6 +372,7 @@ class DatasourceEditorRouter extends React.Component<Props, State> {
|
|||
this.props.discardTempDatasource();
|
||||
this.props.deleteTempDSFromDraft();
|
||||
!!this.state.unblock && this.state.unblock();
|
||||
this.props.resetDefaultKeyValPairFlag();
|
||||
}
|
||||
|
||||
routesBlockFormChangeCallback() {
|
||||
|
|
@ -432,6 +435,31 @@ class DatasourceEditorRouter extends React.Component<Props, State> {
|
|||
!!this.state.unblock && this.state.unblock();
|
||||
}
|
||||
|
||||
initializeFormWithDefaults() {
|
||||
// This is required because once datasource form is loaded, we initialize key value pairs to have default empty values
|
||||
// This initialization makes the form dirty and shows the discard popup on back button click even if the user has not made any changes
|
||||
// This function will initialize redux form with those default empty key value pairs, so when it checks if the form is dirty or not
|
||||
// Both initial and current value will be same and form will not be dirty as expected by user.
|
||||
if (
|
||||
this.props.defaultKeyValueArrayConfig.length > 0 &&
|
||||
!!this.props.initialValue
|
||||
) {
|
||||
const formData: Datasource =
|
||||
this.props.pluginType === "API"
|
||||
? this.props.restAPIFormData
|
||||
: this.props.formData;
|
||||
for (const prop of this.props.defaultKeyValueArrayConfig) {
|
||||
const propPath: string[] = prop.split("[*].");
|
||||
const newValues = _.get(formData, propPath[0], []);
|
||||
_.set(this.props.initialValue, propPath[0], newValues);
|
||||
}
|
||||
|
||||
// since we have consumed key value pair config to initialize datasource form,
|
||||
// below function will reset the config array in redux store
|
||||
this.props.resetDefaultKeyValPairFlag();
|
||||
}
|
||||
}
|
||||
|
||||
renderSaveDisacardModal() {
|
||||
return (
|
||||
<SaveOrDiscardDatasourceModal
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ export default function OnboardingChecklist() {
|
|||
() => ONBOARDING_CHECKLIST_ACTIONS.CONNECT_A_DATASOURCE,
|
||||
)
|
||||
? Category.primary
|
||||
: Category.tertiary
|
||||
: Category.secondary
|
||||
}
|
||||
className="t--checklist-datasource-button"
|
||||
data-testid="checklist-datasource-button"
|
||||
|
|
@ -389,7 +389,7 @@ export default function OnboardingChecklist() {
|
|||
suggestedNextAction ===
|
||||
createMessage(() => ONBOARDING_CHECKLIST_ACTIONS.CREATE_A_QUERY)
|
||||
? Category.primary
|
||||
: Category.tertiary
|
||||
: Category.secondary
|
||||
}
|
||||
className="t--checklist-action-button"
|
||||
data-testid="checklist-action-button"
|
||||
|
|
@ -441,7 +441,7 @@ export default function OnboardingChecklist() {
|
|||
suggestedNextAction ===
|
||||
createMessage(() => ONBOARDING_CHECKLIST_ACTIONS.ADD_WIDGETS)
|
||||
? Category.primary
|
||||
: Category.tertiary
|
||||
: Category.secondary
|
||||
}
|
||||
className="t--checklist-widget-button"
|
||||
data-testid="checklist-widget-button"
|
||||
|
|
@ -491,7 +491,7 @@ export default function OnboardingChecklist() {
|
|||
() => ONBOARDING_CHECKLIST_ACTIONS.CONNECT_DATA_TO_WIDGET,
|
||||
)
|
||||
? Category.primary
|
||||
: Category.tertiary
|
||||
: Category.secondary
|
||||
}
|
||||
className="t--checklist-connection-button"
|
||||
data-testid="checklist-connection-button"
|
||||
|
|
@ -534,7 +534,7 @@ export default function OnboardingChecklist() {
|
|||
() => ONBOARDING_CHECKLIST_ACTIONS.DEPLOY_APPLICATIONS,
|
||||
)
|
||||
? Category.primary
|
||||
: Category.tertiary
|
||||
: Category.secondary
|
||||
}
|
||||
className="t--checklist-deploy-button"
|
||||
data-testid="checklist-deploy-button"
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ function NewApiScreen(props: Props) {
|
|||
src={authApiPlugin.iconLocation}
|
||||
/>
|
||||
</div>
|
||||
<p className="textBtn">Authenticated API</p>
|
||||
<p className="t--plugin-name textBtn">Authenticated API</p>
|
||||
</CardContentWrapper>
|
||||
</ApiCard>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useCallback } from "react";
|
||||
|
||||
import { AppTheme } from "entities/AppTheming";
|
||||
import { ButtonTab, TooltipComponent } from "design-system";
|
||||
import { ButtonGroup, TooltipComponent } from "design-system";
|
||||
import { invertedBorderRadiusOptions } from "constants/ThemeConstants";
|
||||
|
||||
interface ThemeBorderRadiusControlProps {
|
||||
|
|
@ -39,7 +39,7 @@ function ThemeBorderRadiusControl(props: ThemeBorderRadiusControlProps) {
|
|||
? [invertedBorderRadiusOptions[selectedOption]]
|
||||
: [];
|
||||
|
||||
const buttonTabOptions = Object.keys(options).map((optionKey) => ({
|
||||
const buttonGroupOptions = Object.keys(options).map((optionKey) => ({
|
||||
icon: (
|
||||
<TooltipComponent
|
||||
content={optionKey}
|
||||
|
|
@ -56,8 +56,8 @@ function ThemeBorderRadiusControl(props: ThemeBorderRadiusControlProps) {
|
|||
}));
|
||||
|
||||
return (
|
||||
<ButtonTab
|
||||
options={buttonTabOptions}
|
||||
<ButtonGroup
|
||||
options={buttonGroupOptions}
|
||||
selectButton={onChangeBorder}
|
||||
values={selectedOptionKey}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import React, { useCallback } from "react";
|
||||
import { ButtonTab } from "design-system";
|
||||
|
||||
import { AppTheme } from "entities/AppTheming";
|
||||
import { TooltipComponent } from "design-system";
|
||||
import { ButtonGroup, TooltipComponent } from "design-system";
|
||||
import CloseLineIcon from "remixicon-react/CloseLineIcon";
|
||||
import { invertedBoxShadowOptions } from "constants/ThemeConstants";
|
||||
|
||||
|
|
@ -42,7 +40,7 @@ function ThemeBoxShadowControl(props: ThemeBoxShadowControlProps) {
|
|||
? [invertedBoxShadowOptions[selectedOption]]
|
||||
: [];
|
||||
|
||||
const buttonTabOptions = Object.keys(options).map((optionKey) => ({
|
||||
const buttonGroupOptions = Object.keys(options).map((optionKey) => ({
|
||||
icon: (
|
||||
<TooltipComponent
|
||||
content={optionKey}
|
||||
|
|
@ -63,8 +61,8 @@ function ThemeBoxShadowControl(props: ThemeBoxShadowControlProps) {
|
|||
}));
|
||||
|
||||
return (
|
||||
<ButtonTab
|
||||
options={buttonTabOptions}
|
||||
<ButtonGroup
|
||||
options={buttonGroupOptions}
|
||||
selectButton={onChangeShadow}
|
||||
values={selectedOptionKey}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -316,6 +316,13 @@ function ReconnectDatasourceModal() {
|
|||
const [datasource, setDatasource] = useState<Datasource | null>(null);
|
||||
const [isImport, setIsImport] = useState(queryIsImport);
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const queryDS = datasources.find((ds) => ds.id === queryDatasourceId);
|
||||
const dsName = queryDS?.name;
|
||||
const orgId = queryDS?.workspaceId;
|
||||
let pluginName = "";
|
||||
if (!!queryDS?.pluginId) {
|
||||
pluginName = pluginNames[queryDS.pluginId];
|
||||
}
|
||||
|
||||
// when redirecting from oauth, processing the status
|
||||
if (isImport) {
|
||||
|
|
@ -330,6 +337,13 @@ function ReconnectDatasourceModal() {
|
|||
? OAUTH_AUTHORIZATION_APPSMITH_ERROR
|
||||
: OAUTH_AUTHORIZATION_FAILED;
|
||||
Toaster.show({ text: display_message || message, variant });
|
||||
const oAuthStatus = status;
|
||||
AnalyticsUtil.logEvent("UPDATE_DATASOURCE", {
|
||||
dsName,
|
||||
oAuthStatus,
|
||||
orgId,
|
||||
pluginName,
|
||||
});
|
||||
} else if (queryDatasourceId) {
|
||||
dispatch(getOAuthAccessToken(queryDatasourceId));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ import WidgetInfo from "../WidgetInfo";
|
|||
import ForkTemplate from "../ForkTemplate";
|
||||
import { templateIdUrl } from "RouteBuilder";
|
||||
import { useQuery } from "pages/Editor/utils";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getForkableWorkspaces } from "selectors/templatesSelectors";
|
||||
|
||||
export const DescriptionWrapper = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -94,6 +96,7 @@ function TemplateDescription(props: TemplateDescriptionProps) {
|
|||
}>();
|
||||
const history = useHistory();
|
||||
const query = useQuery();
|
||||
const workspaceList = useSelector(getForkableWorkspaces);
|
||||
|
||||
const onForkButtonTrigger = () => {
|
||||
history.replace(
|
||||
|
|
@ -114,7 +117,7 @@ function TemplateDescription(props: TemplateDescriptionProps) {
|
|||
{template.description}
|
||||
</Text>
|
||||
</div>
|
||||
{!props.hideForkButton && (
|
||||
{!props.hideForkButton && !!workspaceList.length && (
|
||||
<ForkTemplate
|
||||
onClose={onForkModalClose}
|
||||
showForkModal={!!query.get(SHOW_FORK_MODAL_PARAM)}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import {
|
|||
} from "@appsmith/constants/messages";
|
||||
import { templateIdUrl } from "RouteBuilder";
|
||||
import { Position } from "@blueprintjs/core";
|
||||
import { getForkableWorkspaces } from "selectors/templatesSelectors";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const TemplateWrapper = styled.div`
|
||||
border: 1px solid ${Colors.GEYSER_LIGHT};
|
||||
|
|
@ -129,6 +131,7 @@ export function TemplateLayout(props: TemplateLayoutProps) {
|
|||
title,
|
||||
} = props.template;
|
||||
const [showForkModal, setShowForkModal] = useState(false);
|
||||
const workspaceList = useSelector(getForkableWorkspaces);
|
||||
const onClick = () => {
|
||||
if (props.onClick) {
|
||||
props.onClick(id);
|
||||
|
|
@ -176,26 +179,29 @@ export function TemplateLayout(props: TemplateLayoutProps) {
|
|||
);
|
||||
})}
|
||||
</TemplateDatasources>
|
||||
<div onClick={onForkButtonTrigger}>
|
||||
<ForkTemplateDialog
|
||||
onClose={onForkModalClose}
|
||||
showForkModal={showForkModal}
|
||||
templateId={id}
|
||||
>
|
||||
<Tooltip
|
||||
content={createMessage(FORK_THIS_TEMPLATE)}
|
||||
minimal
|
||||
position={Position.BOTTOM}
|
||||
{!!workspaceList.length && (
|
||||
<div onClick={onForkButtonTrigger}>
|
||||
<ForkTemplateDialog
|
||||
onClose={onForkModalClose}
|
||||
showForkModal={showForkModal}
|
||||
templateId={id}
|
||||
>
|
||||
<StyledButton
|
||||
className="t--fork-template fork-button"
|
||||
icon="plus"
|
||||
size={Size.medium}
|
||||
tag="button"
|
||||
/>
|
||||
</Tooltip>
|
||||
</ForkTemplateDialog>
|
||||
</div>
|
||||
<Tooltip
|
||||
content={createMessage(FORK_THIS_TEMPLATE)}
|
||||
minimal
|
||||
position={Position.BOTTOM}
|
||||
>
|
||||
<StyledButton
|
||||
className="t--fork-template fork-button"
|
||||
icon="plus"
|
||||
onClick={onForkButtonTrigger}
|
||||
size={Size.medium}
|
||||
tag="button"
|
||||
/>
|
||||
</Tooltip>
|
||||
</ForkTemplateDialog>
|
||||
</div>
|
||||
)}
|
||||
</TemplateContentFooter>
|
||||
</TemplateContent>
|
||||
</TemplateWrapper>
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import { getIsDraggingForSelection } from "selectors/canvasSelectors";
|
|||
import { StickyCanvasArena } from "./StickyCanvasArena";
|
||||
import { getAbsolutePixels } from "utils/helpers";
|
||||
import {
|
||||
getSlidingCanvasName,
|
||||
getStickyCanvasName,
|
||||
getSlidingArenaName,
|
||||
} from "constants/componentClassNameConstants";
|
||||
|
||||
export interface SelectedArenaDimensions {
|
||||
|
|
@ -482,10 +482,10 @@ export function CanvasSelectionArena({
|
|||
return shouldShow ? (
|
||||
<StickyCanvasArena
|
||||
canExtend={canExtend}
|
||||
canvasId={getSlidingCanvasName(widgetId)}
|
||||
canvasId={getStickyCanvasName(widgetId)}
|
||||
canvasPadding={canvasPadding}
|
||||
getRelativeScrollingParent={getNearestParentCanvas}
|
||||
id={getStickyCanvasName(widgetId)}
|
||||
id={getSlidingArenaName(widgetId)}
|
||||
ref={canvasRef}
|
||||
showCanvas={shouldShow}
|
||||
snapColSpace={snapColumnSpace}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getTenantConfig } from "@appsmith/selectors/tenantSelectors";
|
||||
import { getComplementaryGrayscaleColor } from "widgets/WidgetUtils";
|
||||
|
||||
type PageProps = {
|
||||
children?: React.ReactNode;
|
||||
|
|
@ -11,9 +14,16 @@ type PageProps = {
|
|||
|
||||
function Page(props: PageProps) {
|
||||
const { cta, description, errorCode, title } = props;
|
||||
const tenantConfig = useSelector(getTenantConfig);
|
||||
const backgroundColor = tenantConfig.brandColors.background;
|
||||
const textColor = getComplementaryGrayscaleColor(backgroundColor);
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center space-y-6 bg-[color:var(--ads-color-background-secondary)]">
|
||||
<div
|
||||
className={`absolute inset-0 flex flex-col items-center justify-center space-y-6 bg-[color:var(--ads-color-background-secondary)] ${
|
||||
textColor === "white" ? "text-white" : ""
|
||||
}`}
|
||||
>
|
||||
{errorCode && (
|
||||
<div className="-mt-8 flex items-center font-bold text-3xl justify-center w-28 bg-white border aspect-square text-[color:var(--ads-color-brand)]">
|
||||
{errorCode}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { ActionButton } from "pages/Editor/DataSourceEditor/JSONtoForm";
|
|||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
getEntities,
|
||||
getPluginNameFromId,
|
||||
getPluginTypeFromDatasourceId,
|
||||
} from "selectors/entitiesSelector";
|
||||
import {
|
||||
|
|
@ -124,8 +125,11 @@ function DatasourceAuth({
|
|||
? formData?.authType
|
||||
: formData?.datasourceConfiguration?.authentication?.authenticationType;
|
||||
|
||||
const { id: datasourceId, isDeleting } = datasource;
|
||||
const { id: datasourceId, isDeleting, pluginId } = datasource;
|
||||
const applicationId = useSelector(getCurrentApplicationId);
|
||||
const pluginName = useSelector((state: AppState) =>
|
||||
getPluginNameFromId(state, pluginId),
|
||||
);
|
||||
|
||||
const datasourcePermissions = datasource.userPermissions || [];
|
||||
|
||||
|
|
@ -144,6 +148,8 @@ function DatasourceAuth({
|
|||
|
||||
const pageId = (pageIdQuery || pageIdProp) as string;
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
const dsName = datasource?.name;
|
||||
const orgId = datasource?.workspaceId;
|
||||
|
||||
useEffect(() => {
|
||||
if (confirmDelete) {
|
||||
|
|
@ -172,6 +178,13 @@ function DatasourceAuth({
|
|||
? OAUTH_AUTHORIZATION_APPSMITH_ERROR
|
||||
: OAUTH_AUTHORIZATION_FAILED;
|
||||
Toaster.show({ text: display_message || message, variant });
|
||||
const oAuthStatus = status;
|
||||
AnalyticsUtil.logEvent("UPDATE_DATASOURCE", {
|
||||
dsName,
|
||||
oAuthStatus,
|
||||
orgId,
|
||||
pluginName,
|
||||
});
|
||||
} else {
|
||||
dispatch(getOAuthAccessToken(datasourceId));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,14 @@ import useWorkspace from "utils/hooks/useWorkspace";
|
|||
import TooltipWrapper from "pages/Applications/EmbedSnippet/TooltipWrapper";
|
||||
import {
|
||||
createMessage,
|
||||
INVITE_USERS_PLACEHOLDER,
|
||||
IN_APP_EMBED_SETTING,
|
||||
MAKE_APPLICATION_PUBLIC,
|
||||
MAKE_APPLICATION_PUBLIC_TOOLTIP,
|
||||
} from "@appsmith/constants/messages";
|
||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||
|
||||
const { cloudHosting } = getAppsmithConfigs();
|
||||
|
||||
const ShareToggle = styled.div`
|
||||
flex-basis: 46px;
|
||||
|
|
@ -85,6 +89,7 @@ function AppInviteUsersForm(props: any) {
|
|||
{canInviteToWorkspace && (
|
||||
<WorkspaceInviteUsersForm
|
||||
isApplicationInvite
|
||||
placeholder={createMessage(INVITE_USERS_PLACEHOLDER, cloudHosting)}
|
||||
workspaceId={props.workspaceId}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ export interface PartialActionData {
|
|||
isExecuting: Record<string, boolean>;
|
||||
}
|
||||
|
||||
interface JSExecutionData {
|
||||
data: unknown;
|
||||
collectionId: string;
|
||||
actionId: string;
|
||||
}
|
||||
|
||||
// Object of collectionIds to JSExecutionData[]
|
||||
export type BatchedJSExecutionData = Record<string, JSExecutionData[]>;
|
||||
|
||||
const jsActionsReducer = createReducer(initialState, {
|
||||
[ReduxActionTypes.FETCH_JS_ACTIONS_SUCCESS]: (
|
||||
state: JSCollectionDataState,
|
||||
|
|
@ -292,7 +301,6 @@ const jsActionsReducer = createReducer(initialState, {
|
|||
[ReduxActionTypes.EXECUTE_JS_FUNCTION_SUCCESS]: (
|
||||
state: JSCollectionDataState,
|
||||
action: ReduxAction<{
|
||||
results: any;
|
||||
collectionId: string;
|
||||
actionId: string;
|
||||
isDirty: boolean;
|
||||
|
|
@ -302,10 +310,6 @@ const jsActionsReducer = createReducer(initialState, {
|
|||
if (a.config.id === action.payload.collectionId) {
|
||||
return {
|
||||
...a,
|
||||
data: {
|
||||
...a.data,
|
||||
[action.payload.actionId]: action.payload.results,
|
||||
},
|
||||
isExecuting: {
|
||||
...a.isExecuting,
|
||||
[action.payload.actionId]: false,
|
||||
|
|
@ -318,6 +322,26 @@ const jsActionsReducer = createReducer(initialState, {
|
|||
}
|
||||
return a;
|
||||
}),
|
||||
[ReduxActionTypes.SET_JS_FUNCTION_EXECUTION_DATA]: (
|
||||
state: JSCollectionDataState,
|
||||
action: ReduxAction<BatchedJSExecutionData>,
|
||||
): JSCollectionDataState =>
|
||||
state.map((jsCollectionData) => {
|
||||
const collectionId = jsCollectionData.config.id;
|
||||
if (collectionId in action.payload) {
|
||||
let data = {
|
||||
...jsCollectionData.data,
|
||||
};
|
||||
action.payload[collectionId].forEach((item) => {
|
||||
data = { ...data, [item.actionId]: item.data };
|
||||
});
|
||||
return {
|
||||
...jsCollectionData,
|
||||
data,
|
||||
};
|
||||
}
|
||||
return jsCollectionData;
|
||||
}),
|
||||
[ReduxActionTypes.UPDATE_JS_FUNCTION_PROPERTY_SUCCESS]: (
|
||||
state: JSCollectionDataState,
|
||||
action: ReduxAction<{ collection: JSCollection }>,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const initialState: DatasourcePaneReduxState = {
|
|||
newDatasource: "",
|
||||
viewMode: true,
|
||||
collapsibleState: {},
|
||||
defaultKeyValueArrayConfig: [],
|
||||
};
|
||||
|
||||
export interface DatasourcePaneReduxState {
|
||||
|
|
@ -27,6 +28,7 @@ export interface DatasourcePaneReduxState {
|
|||
newDatasource: string;
|
||||
viewMode: boolean;
|
||||
collapsibleState: Record<string, boolean>;
|
||||
defaultKeyValueArrayConfig: Array<string>;
|
||||
}
|
||||
|
||||
const datasourcePaneReducer = createReducer(initialState, {
|
||||
|
|
@ -137,6 +139,25 @@ const datasourcePaneReducer = createReducer(initialState, {
|
|||
expandDatasourceId: action.payload,
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET]: (
|
||||
state: DatasourcePaneReduxState,
|
||||
action: ReduxAction<string>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
defaultKeyValueArrayConfig: state.defaultKeyValueArrayConfig.concat(
|
||||
action.payload,
|
||||
),
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.RESET_DATASOURCE_DEFAULT_KEY_VALUE_PAIR_SET]: (
|
||||
state: DatasourcePaneReduxState,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
defaultKeyValueArrayConfig: [],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default datasourcePaneReducer;
|
||||
|
|
|
|||
|
|
@ -536,7 +536,9 @@ function* testDatasourceSaga(actionPayload: ReduxAction<Datasource>) {
|
|||
id: actionPayload.payload.id as any,
|
||||
};
|
||||
|
||||
if (!equal(initialValues, values)) {
|
||||
// when datasource is not yet saved by user, datasource id is temporary
|
||||
// for temporary datasource, we do not need to pass datasource id in test api call
|
||||
if (!equal(initialValues, values) || datasource?.id === TEMP_DATASOURCE_ID) {
|
||||
delete payload.id;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ import {
|
|||
EvalTreeRequestData,
|
||||
EvalTreeResponseData,
|
||||
} from "workers/Evaluation/types";
|
||||
import { BatchedJSExecutionData } from "reducers/entityReducers/jsActionsReducer";
|
||||
import { sortJSExecutionDataByCollectionId } from "workers/Evaluation/JSObject/utils";
|
||||
import { MessageType, TMessage } from "utils/MessageUtil";
|
||||
|
||||
const evalWorker = new GracefulWorkerService(
|
||||
|
|
@ -365,6 +367,16 @@ export function* handleEvalWorkerMessage(message: TMessage<any>) {
|
|||
);
|
||||
break;
|
||||
}
|
||||
case MAIN_THREAD_ACTION.PROCESS_JS_FUNCTION_EXECUTION: {
|
||||
const sortedData: BatchedJSExecutionData = yield sortJSExecutionDataByCollectionId(
|
||||
data.JSData as Record<string, unknown>,
|
||||
);
|
||||
yield put({
|
||||
type: ReduxActionTypes.SET_JS_FUNCTION_EXECUTION_DATA,
|
||||
payload: sortedData,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case MAIN_THREAD_ACTION.PROCESS_TRIGGER: {
|
||||
const { eventType, trigger, triggerMeta } = data;
|
||||
log.debug({ trigger: data.trigger });
|
||||
|
|
|
|||
|
|
@ -379,7 +379,6 @@ export function* handleExecuteJSFunctionSaga(data: {
|
|||
yield put({
|
||||
type: ReduxActionTypes.EXECUTE_JS_FUNCTION_SUCCESS,
|
||||
payload: {
|
||||
results: result,
|
||||
collectionId,
|
||||
actionId,
|
||||
isDirty,
|
||||
|
|
@ -394,6 +393,20 @@ export function* handleExecuteJSFunctionSaga(data: {
|
|||
},
|
||||
state: { response: result },
|
||||
});
|
||||
if (!action.actionConfiguration.isAsync) {
|
||||
yield put({
|
||||
type: ReduxActionTypes.SET_JS_FUNCTION_EXECUTION_DATA,
|
||||
payload: {
|
||||
[collectionId]: [
|
||||
{
|
||||
data: result,
|
||||
collectionId,
|
||||
actionId,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
appMode === APP_MODE.EDIT &&
|
||||
!isDirty &&
|
||||
Toaster.show({
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ function logLatestEvalPropertyErrors(
|
|||
}
|
||||
|
||||
const idField = isWidget(entity) ? entity.widgetId : entity.actionId;
|
||||
const nameField = isWidget(entity) ? entity.widgetName : entity.name;
|
||||
const nameField = isWidget(entity) ? entity.widgetName : entityName;
|
||||
const entityType = isWidget(entity)
|
||||
? ENTITY_TYPE.WIDGET
|
||||
: isAction(entity)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user