Merge pull request #22936 from appsmithorg/ci/release-frozen-1.9.18

ci: Promotional PR
This commit is contained in:
Trisha Anand 2023-05-09 16:09:10 +05:30 committed by GitHub
commit 3cb8d21c1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
292 changed files with 19873 additions and 16794 deletions

View File

@ -3,7 +3,7 @@ name: Cypress Add Known failed tests
on:
issues:
types: [opened, closed, reopened]
jobs:
IssueOpened:
if: (github.event.action == 'opened' || github.event.action == 'reopened') && contains( github.event.issue.labels.*.name, 'CI impacted')
@ -19,14 +19,16 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
XATATOKEN: ${{ secrets.XATA_TOKEN }}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
run: |
echo "Issue title: ${{ github.event.issue.title }}"
echo "Issue body: ${{ github.event.issue.body }}"
echo "Issue title: $ISSUE_TITLE"
echo "Issue body: $ISSUE_BODY"
#echo "$GITHUB_CONTEXT"
chmod a+x app/client/cypress/xataadd.sh
echo "${{ github.event.issue.title }}"|awk '{print $2}'
echo "${{ github.event.issue.title }}"|awk '{print $2}'|xargs app/client/cypress/xataadd.sh
echo "$ISSUE_TITLE"|awk '{print $2}'
echo "$ISSUE_TITLE"|awk '{print $2}'|xargs app/client/cypress/xataadd.sh
IssueClosed:
if: github.event.action == 'closed' && contains( github.event.issue.labels.*.name, 'CI impacted')
runs-on: ubuntu-latest
@ -41,12 +43,11 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
XATATOKEN: ${{ secrets.XATA_TOKEN }}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
run: |
echo "Issue title: ${{ github.event.issue.title }}"
echo "Issue body: ${{ github.event.issue.body }}"
echo "Issue title: $ISSUE_TITLE"
echo "Issue body: $ISSUE_BODY"
#echo "$GITHUB_CONTEXT"
chmod a+x app/client/cypress/xatadel.sh
echo "${{ github.event.issue.title }}"|awk '{print $2}'|xargs app/client/cypress/xatadel.sh
echo "$ISSUE_TITLE"|awk '{print $2}'|xargs app/client/cypress/xatadel.sh

View File

@ -159,8 +159,8 @@ Lets build great software together.
[![Nikhil-Nandagopal](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/3897254?v=4&w=50&h=50&mask=circle)](https://github.com/Nikhil-Nandagopal)
[![mohanarpit](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/458946?v=4&w=50&h=50&mask=circle)](https://github.com/mohanarpit)
[![hetunandu](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/12022471?v=4&w=50&h=50&mask=circle)](https://github.com/hetunandu)
[![trishaanand](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/8403079?v=4&w=50&h=50&mask=circle)](https://github.com/trishaanand)
[![sharat87](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/120119?v=4&w=50&h=50&mask=circle)](https://github.com/sharat87)
[![trishaanand](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/8403079?v=4&w=50&h=50&mask=circle)](https://github.com/trishaanand)
[![riodeuno](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/103687?v=4&w=50&h=50&mask=circle)](https://github.com/riodeuno)
[![vicky-primathon](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/67091118?v=4&w=50&h=50&mask=circle)](https://github.com/vicky-primathon)
[![akash-codemonk](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/67054171?v=4&w=50&h=50&mask=circle)](https://github.com/akash-codemonk)
@ -171,8 +171,8 @@ Lets build great software together.
[![AnaghHegde](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/12005551?v=4&w=50&h=50&mask=circle)](https://github.com/AnaghHegde)
[![NandanAnantharamu](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/67676905?v=4&w=50&h=50&mask=circle)](https://github.com/NandanAnantharamu)
[![arunvjn](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/32433245?v=4&w=50&h=50&mask=circle)](https://github.com/arunvjn)
[![nayan-rafiq](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/83352306?v=4&w=50&h=50&mask=circle)](https://github.com/nayan-rafiq)
[![Aishwarya-U-R](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/91450662?v=4&w=50&h=50&mask=circle)](https://github.com/Aishwarya-U-R)
[![nayan-rafiq](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/83352306?v=4&w=50&h=50&mask=circle)](https://github.com/nayan-rafiq)
[![abhvsn](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/41686026?v=4&w=50&h=50&mask=circle)](https://github.com/abhvsn)
[![jsartisan](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/6636360?v=4&w=50&h=50&mask=circle)](https://github.com/jsartisan)
[![ankitakinger](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/28362912?v=4&w=50&h=50&mask=circle)](https://github.com/ankitakinger)
@ -183,8 +183,8 @@ Lets build great software together.
[![sbalaji1192](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/5328605?v=4&w=50&h=50&mask=circle)](https://github.com/sbalaji1192)
[![Irongade](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/37867493?v=4&w=50&h=50&mask=circle)](https://github.com/Irongade)
[![SatishGandham](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/441914?v=4&w=50&h=50&mask=circle)](https://github.com/SatishGandham)
[![yatinappsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/84702014?v=4&w=50&h=50&mask=circle)](https://github.com/yatinappsmith)
[![prsidhu](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/5424788?v=4&w=50&h=50&mask=circle)](https://github.com/prsidhu)
[![yatinappsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/84702014?v=4&w=50&h=50&mask=circle)](https://github.com/yatinappsmith)
[![sidhantgoel](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/3933675?v=4&w=50&h=50&mask=circle)](https://github.com/sidhantgoel)
[![somangshu](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/11089579?v=4&w=50&h=50&mask=circle)](https://github.com/somangshu)
[![ApekshaBhosale](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/7846888?v=4&w=50&h=50&mask=circle)](https://github.com/ApekshaBhosale)
@ -193,47 +193,45 @@ Lets build great software together.
[![Parthvi12](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/80334441?v=4&w=50&h=50&mask=circle)](https://github.com/Parthvi12)
[![marks0351](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/35134347?v=4&w=50&h=50&mask=circle)](https://github.com/marks0351)
[![albinAppsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/87797149?v=4&w=50&h=50&mask=circle)](https://github.com/albinAppsmith)
[![ashit-rath](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/88306433?v=4&w=50&h=50&mask=circle)](https://github.com/ashit-rath)
[![sarojsarab](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/43822041?v=4&w=50&h=50&mask=circle)](https://github.com/sarojsarab)
[![AmanAgarwal041](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/7565635?v=4&w=50&h=50&mask=circle)](https://github.com/AmanAgarwal041)
[![eco-monk](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/66776129?v=4&w=50&h=50&mask=circle)](https://github.com/eco-monk)
[![ashit-rath](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/88306433?v=4&w=50&h=50&mask=circle)](https://github.com/ashit-rath)
[![ayushpahwa](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/8526215?v=4&w=50&h=50&mask=circle)](https://github.com/ayushpahwa)
[![sarojsarab](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/43822041?v=4&w=50&h=50&mask=circle)](https://github.com/sarojsarab)
[![eco-monk](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/66776129?v=4&w=50&h=50&mask=circle)](https://github.com/eco-monk)
[![berzerkeer](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/74818788?v=4&w=50&h=50&mask=circle)](https://github.com/berzerkeer)
[![areyabhishek](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/30255708?v=4&w=50&h=50&mask=circle)](https://github.com/areyabhishek)
[![keyurparalkar](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/14138515?v=4&w=50&h=50&mask=circle)](https://github.com/keyurparalkar)
[![rimildeyjsr](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/10229595?v=4&w=50&h=50&mask=circle)](https://github.com/rimildeyjsr)
[![vishnu-gp](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/9128194?v=4&w=50&h=50&mask=circle)](https://github.com/vishnu-gp)
[![berzerkeer](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/74818788?v=4&w=50&h=50&mask=circle)](https://github.com/berzerkeer)
[![sneha122](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/30018882?v=4&w=50&h=50&mask=circle)](https://github.com/sneha122)
[![ChandanBalajiBP](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/104058110?v=4&w=50&h=50&mask=circle)](https://github.com/ChandanBalajiBP)
[![pratapaprasanna](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/15846947?v=4&w=50&h=50&mask=circle)](https://github.com/pratapaprasanna)
[![megaconfidence](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/17744578?v=4&w=50&h=50&mask=circle)](https://github.com/megaconfidence)
[![sum35h](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/20785806?v=4&w=50&h=50&mask=circle)](https://github.com/sum35h)
[![nsarupr](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/20905988?v=4&w=50&h=50&mask=circle)](https://github.com/nsarupr)
[![vihar](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/16307796?v=4&w=50&h=50&mask=circle)](https://github.com/vihar)
[![subrata71](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/3524599?v=4&w=50&h=50&mask=circle)](https://github.com/subrata71)
[![dhruvikn](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/22471214?v=4&w=50&h=50&mask=circle)](https://github.com/dhruvikn)
[![nsarupr](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/20905988?v=4&w=50&h=50&mask=circle)](https://github.com/nsarupr)
[![Vijetha-Kaja](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/119562824?v=4&w=50&h=50&mask=circle)](https://github.com/Vijetha-Kaja)
[![dhruvikn](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/22471214?v=4&w=50&h=50&mask=circle)](https://github.com/dhruvikn)
[![tanvibhakta](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/13763558?v=4&w=50&h=50&mask=circle)](https://github.com/tanvibhakta)
[![NilanshBansal](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/25542733?v=4&w=50&h=50&mask=circle)](https://github.com/NilanshBansal)
[![sondermanish](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/107841575?v=4&w=50&h=50&mask=circle)](https://github.com/sondermanish)
[![prapullac](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/71753653?v=4&w=50&h=50&mask=circle)](https://github.com/prapullac)
[![Druthi](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/20187542?v=4&w=50&h=50&mask=circle)](https://github.com/Druthi)
[![vsvamsi1](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/121419957?v=4&w=50&h=50&mask=circle)](https://github.com/vsvamsi1)
[![rohitagarwal88](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/890915?v=4&w=50&h=50&mask=circle)](https://github.com/rohitagarwal88)
[![Druthi](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/20187542?v=4&w=50&h=50&mask=circle)](https://github.com/Druthi)
[![ravikp7](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/13567359?v=4&w=50&h=50&mask=circle)](https://github.com/ravikp7)
[![PiyushPushkar02](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/118709669?v=4&w=50&h=50&mask=circle)](https://github.com/PiyushPushkar02)
[![rajatagrawal](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/1189106?v=4&w=50&h=50&mask=circle)](https://github.com/rajatagrawal)
[![KelvinOm](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/11555074?v=4&w=50&h=50&mask=circle)](https://github.com/KelvinOm)
[![Pranay105](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/48308728?v=4&w=50&h=50&mask=circle)](https://github.com/Pranay105)
[![PiyushPushkar02](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/118709669?v=4&w=50&h=50&mask=circle)](https://github.com/PiyushPushkar02)
[![rohitagarwal88](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/890915?v=4&w=50&h=50&mask=circle)](https://github.com/rohitagarwal88)
[![ankitsrivas14](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/67647761?v=4&w=50&h=50&mask=circle)](https://github.com/ankitsrivas14)
[![Pranay105](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/48308728?v=4&w=50&h=50&mask=circle)](https://github.com/Pranay105)
[![ramsaptami](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/79509062?v=4&w=50&h=50&mask=circle)](https://github.com/ramsaptami)
[![sanveer-osahan](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/28753975?v=4&w=50&h=50&mask=circle)](https://github.com/sanveer-osahan)
[![ichik](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/80973?v=4&w=50&h=50&mask=circle)](https://github.com/ichik)
[![rahulbarwal](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/6761673?v=4&w=50&h=50&mask=circle)](https://github.com/rahulbarwal)
[![rohan-arthur](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/94514895?v=4&w=50&h=50&mask=circle)](https://github.com/rohan-arthur)
[![sanveer-osahan](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/28753975?v=4&w=50&h=50&mask=circle)](https://github.com/sanveer-osahan)
[![dipyamanbiswas07](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/26247571?v=4&w=50&h=50&mask=circle)](https://github.com/dipyamanbiswas07)
[![vivonk](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/25587962?v=4&w=50&h=50&mask=circle)](https://github.com/vivonk)
[![rahulbarwal](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/6761673?v=4&w=50&h=50&mask=circle)](https://github.com/rahulbarwal)
[![kocharrahul7](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/20532920?v=4&w=50&h=50&mask=circle)](https://github.com/kocharrahul7)
[![rohan-arthur](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/94514895?v=4&w=50&h=50&mask=circle)](https://github.com/rohan-arthur)
[![AS-Laguna](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/101155659?v=4&w=50&h=50&mask=circle)](https://github.com/AS-Laguna)
[![jacquesikot](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/40626453?v=4&w=50&h=50&mask=circle)](https://github.com/jacquesikot)
[![RakshaKShetty](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/45958978?v=4&w=50&h=50&mask=circle)](https://github.com/RakshaKShetty)
@ -265,7 +263,7 @@ Lets build great software together.
[![AnandiKulkarni](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/80756091?v=4&w=50&h=50&mask=circle)](https://github.com/AnandiKulkarni)
[![momcilo-appsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/81744497?v=4&w=50&h=50&mask=circle)](https://github.com/momcilo-appsmith)
[![shwetha-ramesh](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/92293815?v=4&w=50&h=50&mask=circle)](https://github.com/shwetha-ramesh)
[![vasanth-appsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/92305123?v=4&w=50&h=50&mask=circle)](https://github.com/vasanth-appsmith)
[![vasanthappsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/92305123?v=4&w=50&h=50&mask=circle)](https://github.com/vasanthappsmith)
[![parth-appsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/92779003?v=4&w=50&h=50&mask=circle)](https://github.com/parth-appsmith)
[![Richarex](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/93259714?v=4&w=50&h=50&mask=circle)](https://github.com/Richarex)
[![chandannkumar](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/95341241?v=4&w=50&h=50&mask=circle)](https://github.com/chandannkumar)
@ -285,6 +283,7 @@ Lets build great software together.
[![abhiappsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/129862317?v=4&w=50&h=50&mask=circle)](https://github.com/abhiappsmith)
[![deepikaappsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/130959931?v=4&w=50&h=50&mask=circle)](https://github.com/deepikaappsmith)
[![tkAppsmith](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/131347120?v=4&w=50&h=50&mask=circle)](https://github.com/tkAppsmith)
[![prapullc](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/132243297?v=4&w=50&h=50&mask=circle)](https://github.com/prapullc)
[![rishabhsaxena](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/1944800?v=4&w=50&h=50&mask=circle)](https://github.com/rishabhsaxena)
[![wmdev0808](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/82799722?v=4&w=50&h=50&mask=circle)](https://github.com/wmdev0808)
[![techbhavin](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/58818598?v=4&w=50&h=50&mask=circle)](https://github.com/techbhavin)
@ -295,6 +294,7 @@ Lets build great software together.
[![rashmigowda55](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/65769804?v=4&w=50&h=50&mask=circle)](https://github.com/rashmigowda55)
[![ankurrsinghal](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/17961105?v=4&w=50&h=50&mask=circle)](https://github.com/ankurrsinghal)
[![geekup-legodevops](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/72587752?v=4&w=50&h=50&mask=circle)](https://github.com/geekup-legodevops)
[![vihar](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/16307796?v=4&w=50&h=50&mask=circle)](https://github.com/vihar)
[![danieldare](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/25982036?v=4&w=50&h=50&mask=circle)](https://github.com/danieldare)
[![Nikhil-Curefit](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/30792005?v=4&w=50&h=50&mask=circle)](https://github.com/Nikhil-Curefit)
[![souma-ghosh](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/103924539?v=4&w=50&h=50&mask=circle)](https://github.com/souma-ghosh)
@ -303,6 +303,7 @@ Lets build great software together.
[![leotom2000](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/8027694?v=4&w=50&h=50&mask=circle)](https://github.com/leotom2000)
[![Adityaacharya1807](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/32693902?v=4&w=50&h=50&mask=circle)](https://github.com/Adityaacharya1807)
[![RashmiNagarajp](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/61830113?v=4&w=50&h=50&mask=circle)](https://github.com/RashmiNagarajp)
[![prapullac](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/71753653?v=4&w=50&h=50&mask=circle)](https://github.com/prapullac)
[![kaushik94](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/6545467?v=4&w=50&h=50&mask=circle)](https://github.com/kaushik94)
[![akshayrangasaid](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/76783810?v=4&w=50&h=50&mask=circle)](https://github.com/akshayrangasaid)
[![mojtab23](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/5852362?v=4&w=50&h=50&mask=circle)](https://github.com/mojtab23)
@ -350,6 +351,7 @@ Lets build great software together.
[![nuwan94](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/25694570?v=4&w=50&h=50&mask=circle)](https://github.com/nuwan94)
[![OmkarPh](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/48476025?v=4&w=50&h=50&mask=circle)](https://github.com/OmkarPh)
[![parthiv11](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/75653580?v=4&w=50&h=50&mask=circle)](https://github.com/parthiv11)
[![priyanka-mahour](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/43825112?v=4&w=50&h=50&mask=circle)](https://github.com/priyanka-mahour)
[![rafaeelaudibert](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/32079912?v=4&w=50&h=50&mask=circle)](https://github.com/rafaeelaudibert)
[![samyakjain10](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/56185041?v=4&w=50&h=50&mask=circle)](https://github.com/samyakjain10)
[![Jain-Sanchit](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/31254015?v=4&w=50&h=50&mask=circle)](https://github.com/Jain-Sanchit)
@ -373,6 +375,7 @@ Lets build great software together.
[![apoorv-mishra](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/15694566?v=4&w=50&h=50&mask=circle)](https://github.com/apoorv-mishra)
[![anvaravind](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/12210689?v=4&w=50&h=50&mask=circle)](https://github.com/anvaravind)
[![ari-hacks](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/36749814?v=4&w=50&h=50&mask=circle)](https://github.com/ari-hacks)
[![arunstar](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/21214162?v=4&w=50&h=50&mask=circle)](https://github.com/arunstar)
[![ashwanisindhu1](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/549817?v=4&w=50&h=50&mask=circle)](https://github.com/ashwanisindhu1)
[![Caitlin-Fotheringham](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/49273562?v=4&w=50&h=50&mask=circle)](https://github.com/Caitlin-Fotheringham)
[![Chiradeep-Banik](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/76490903?v=4&w=50&h=50&mask=circle)](https://github.com/Chiradeep-Banik)
@ -382,6 +385,7 @@ Lets build great software together.
[![DiptoChakrabarty](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/45638240?v=4&w=50&h=50&mask=circle)](https://github.com/DiptoChakrabarty)
[![felixsuarez0727](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/25110207?v=4&w=50&h=50&mask=circle)](https://github.com/felixsuarez0727)
[![gitstart](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/1501599?v=4&w=50&h=50&mask=circle)](https://github.com/gitstart)
[![harshmange44](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/47944044?v=4&w=50&h=50&mask=circle)](https://github.com/harshmange44)
[![ishaanmehta4](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/61118240?v=4&w=50&h=50&mask=circle)](https://github.com/ishaanmehta4)
[![iamakulov](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/2953267?v=4&w=50&h=50&mask=circle)](https://github.com/iamakulov)
[![jarimayenburg](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/11874892?v=4&w=50&h=50&mask=circle)](https://github.com/jarimayenburg)
@ -407,7 +411,6 @@ Lets build great software together.
[![paususe](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/50680111?v=4&w=50&h=50&mask=circle)](https://github.com/paususe)
[![neok](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/600233?v=4&w=50&h=50&mask=circle)](https://github.com/neok)
[![sanchezpili6](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/37568592?v=4&w=50&h=50&mask=circle)](https://github.com/sanchezpili6)
[![priyanka-mahour](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/43825112?v=4&w=50&h=50&mask=circle)](https://github.com/priyanka-mahour)
[![pushkar1393](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/31943620?v=4&w=50&h=50&mask=circle)](https://github.com/pushkar1393)
[![imor](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/1666073?v=4&w=50&h=50&mask=circle)](https://github.com/imor)
[![ricardocarrola](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/11631915?v=4&w=50&h=50&mask=circle)](https://github.com/ricardocarrola)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,7 @@ describe("AForce - Community Issues page validations", function () {
homePage.AssertImportToast();
}
//Validate table is not empty!
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
});
//Validating order of header columns!
@ -74,7 +74,7 @@ describe("AForce - Community Issues page validations", function () {
});
deployMode.DeployApp();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
//Verify hidden columns are infact hidden in deployed app!
table.AssertTableHeaderOrder(
@ -83,38 +83,38 @@ describe("AForce - Community Issues page validations", function () {
table.AssertSelectedRow(selectedRow); //Assert default selected row
table.AssertPageNumber(1);
table.NavigateToNextPage(); //page 2
table.AssertPageNumber(1, "On", "v2");
table.NavigateToNextPage(true, "v2"); //page 2
agHelper.Sleep(3000); //wait for table navigation to take effect!
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.AssertSelectedRow(selectedRow);
table.NavigateToNextPage(); //page 3
table.NavigateToNextPage(true, "v2"); //page 3
agHelper.Sleep(3000); //wait for table navigation to take effect!
table.WaitForTableEmpty(); //page 3
table.NavigateToPreviousPage(); //page 2
table.WaitForTableEmpty("v2"); //page 3
table.NavigateToPreviousPage(true, "v2"); //page 2
agHelper.Sleep(3000); //wait for table navigation to take effect!
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.AssertSelectedRow(selectedRow);
table.NavigateToPreviousPage(); //page 1
table.NavigateToPreviousPage(true, "v2"); //page 1
agHelper.Sleep(3000); //wait for table navigation to take effect!
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.AssertSelectedRow(selectedRow);
table.AssertPageNumber(1);
table.AssertPageNumber(1, "On", "v2");
});
it("3. Validate table navigation with Server Side pagination disabled with Default selected row selection", () => {
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
ee.SelectEntityByName("Table1", "Widgets");
propPane.ToggleOnOrOff("serversidepagination", "Off");
deployMode.DeployApp();
table.WaitUntilTableLoad();
table.AssertPageNumber(1, "Off");
table.WaitUntilTableLoad(0, 0, "v2");
table.AssertPageNumber(1, "Off", "v2");
table.AssertSelectedRow(selectedRow);
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
ee.SelectEntityByName("Table1", "Widgets");
propPane.ToggleOnOrOff("serversidepagination", "On");
});
@ -122,14 +122,14 @@ describe("AForce - Community Issues page validations", function () {
it("4. Change Default selected row in table and verify", () => {
propPane.UpdatePropertyFieldValue("Default Selected Row", "1");
deployMode.DeployApp();
table.WaitUntilTableLoad();
table.AssertPageNumber(1);
table.WaitUntilTableLoad(0, 0, "v2");
table.AssertPageNumber(1, "On", "v2");
table.AssertSelectedRow(1);
table.NavigateToNextPage(); //page 2
table.AssertPageNumber(2);
table.NavigateToNextPage(true, "v2"); //page 2
table.AssertPageNumber(2, "On", "v2");
table.AssertSelectedRow(1);
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
});
it.skip("5. Verify Default search text in table as per 'Default Search Text' property set + Bug 12228", () => {
@ -138,8 +138,8 @@ describe("AForce - Community Issues page validations", function () {
propPane.TypeTextIntoField("Default Search Text", "Bug");
deployMode.DeployApp();
table.AssertSearchText("Bug");
table.WaitUntilTableLoad();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.WaitUntilTableLoad(0, 0, "v2");
deployMode.NavigateBacktoEditor();
ee.SelectEntityByName("Table1", "Widgets");
@ -148,22 +148,22 @@ describe("AForce - Community Issues page validations", function () {
deployMode.DeployApp();
table.AssertSearchText("Question");
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
ee.SelectEntityByName("Table1", "Widgets");
//propPane.EnterJSContext("Default Search Text", "Epic", false);
propPane.TypeTextIntoField("Default Search Text", "Epic"); //Bug 12228 - Searching based on hidden column value should not be allowed
deployMode.DeployApp();
table.AssertSearchText("Epic");
table.WaitForTableEmpty();
table.WaitForTableEmpty("v2");
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
ee.SelectEntityByName("Table1", "Widgets");
propPane.RemoveText("defaultsearchtext");
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
});
it.skip("6. Validate Search table with Client Side Search enabled & disabled", () => {
@ -171,35 +171,35 @@ describe("AForce - Community Issues page validations", function () {
agHelper.AssertExistingToggleState("enableclientsidesearch", "checked");
deployMode.DeployApp();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.SearchTable("Bug");
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
cy.xpath(table._searchBoxCross).click();
table.SearchTable("Question");
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
cy.xpath(table._searchBoxCross).click();
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
ee.SelectEntityByName("Table1", "Widgets");
propPane.ToggleOnOrOff("enableclientsidesearch", "Off");
deployMode.DeployApp();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.SearchTable("Bug");
table.WaitForTableEmpty();
table.WaitForTableEmpty("v2");
cy.xpath(table._searchBoxCross).click();
table.SearchTable("Question");
table.WaitForTableEmpty();
table.WaitForTableEmpty("v2");
cy.xpath(table._searchBoxCross).click();
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
ee.SelectEntityByName("Table1", "Widgets");
propPane.ToggleOnOrOff("enableclientsidesearch", "On");
});
@ -207,32 +207,32 @@ describe("AForce - Community Issues page validations", function () {
it("7. Validate Filter table", () => {
let filterTitle = new Array();
deployMode.DeployApp();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
//One filter
table.OpenNFilterTable("Type", "is exactly", "Bug");
for (let i = 0; i < 3; i++) {
table.ReadTableRowColumnData(i, 0).then(($cellData) => {
table.ReadTableRowColumnData(i, 0, "v2").then(($cellData) => {
expect($cellData).to.eq("Bug");
});
}
table.RemoveFilterNVerify("Question", true, false);
table.RemoveFilterNVerify("Question", true, false, 0, "v2");
//Two filters - OR
table.OpenNFilterTable("Type", "starts with", "Trouble");
for (let i = 0; i < 5; i++) {
table.ReadTableRowColumnData(i, 0).then(($cellData) => {
table.ReadTableRowColumnData(i, 0, "v2").then(($cellData) => {
expect($cellData).to.eq("Troubleshooting");
});
}
table.OpenNFilterTable("Title", "contains", "query", "OR", 1);
table.ReadTableRowColumnData(1, 0).then(($cellData) => {
table.ReadTableRowColumnData(1, 0, "v2").then(($cellData) => {
expect($cellData).to.be.oneOf(["Troubleshooting", "Question"]);
});
for (let i = 0; i < 8; i++) {
table.ReadTableRowColumnData(i, 1, "v1", 100).then(($cellData) => {
table.ReadTableRowColumnData(i, 1, "v2", 100).then(($cellData) => {
if ($cellData.toLowerCase().includes("query"))
filterTitle.push($cellData);
});
@ -240,26 +240,26 @@ describe("AForce - Community Issues page validations", function () {
cy.wrap(filterTitle).as("filterTitleText"); // alias it for later
cy.get("@filterTitleText").its("length").should("eq", 2);
table.RemoveFilterNVerify("Question", true, false);
table.RemoveFilterNVerify("Question", true, false, 0, "v2");
//Two filters - AND
table.OpenNFilterTable("Votes", "greater than", "2");
table.ReadTableRowColumnData(0, 1, "v1", 3000).then(($cellData) => {
table.ReadTableRowColumnData(0, 1, "v2", 3000).then(($cellData) => {
expect($cellData).to.eq("Combine queries from different datasources");
});
table.OpenNFilterTable("Title", "contains", "button", "AND", 1);
table.ReadTableRowColumnData(0, 1, "v1", 3000).then(($cellData) => {
table.ReadTableRowColumnData(0, 1, "v2", 3000).then(($cellData) => {
expect($cellData).to.eq(
"Change the video in the video player with a button click",
);
});
table.RemoveFilterNVerify("Question", true, false);
table.RemoveFilterNVerify("Question", true, false, 0, "v2");
});
it("8. Validate Adding a New issue from Add Modal", () => {
// agHelper.DeployApp()
// table.WaitUntilTableLoad()
// table.WaitUntilTableLoad(0,0,"v2")
cy.get(table._addIcon).closest("div").click();
agHelper.AssertElementVisible(locator._modal);
@ -292,13 +292,13 @@ describe("AForce - Community Issues page validations", function () {
agHelper.AssertElementAbsence(locator._toastMsg); //Making sure internal api doesnt throw error
agHelper.Sleep(3000);
table.SearchTable("Suggestion", 2);
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 0, "v2");
table.ReadTableRowColumnData(0, 0, "v1", 4000).then((cellData) => {
table.ReadTableRowColumnData(0, 0, "v2", 4000).then((cellData) => {
expect(cellData).to.be.equal("Suggestion");
});
table.ReadTableRowColumnData(0, 1).then((cellData) => {
table.ReadTableRowColumnData(0, 1, "v2").then((cellData) => {
expect(cellData).to.be.equal("Adding Title Suggestion via script");
});
});
@ -306,7 +306,7 @@ describe("AForce - Community Issues page validations", function () {
it("9. Validate Updating issue from Details tab & Verify multiselect widget selected values", () => {
agHelper.AssertElementAbsence(locator._widgetInDeployed("tabswidget"));
agHelper.Sleep(2000);
table.SelectTableRow(0, 1);
table.SelectTableRow(0, 1, true, "v2");
agHelper.AssertElementVisible(locator._widgetInDeployed("tabswidget"));
agHelper
.GetNClick(locator._inputWidgetv1InDeployed, 0, true, 0)
@ -355,11 +355,11 @@ describe("AForce - Community Issues page validations", function () {
);
agHelper.ClickButton("Save");
agHelper.Sleep(2000);
table.ReadTableRowColumnData(0, 0, "v1", 2000).then((cellData) => {
table.ReadTableRowColumnData(0, 0, "v2", 2000).then((cellData) => {
expect(cellData).to.be.equal("Troubleshooting");
});
table.ReadTableRowColumnData(0, 1).then((cellData) => {
table.ReadTableRowColumnData(0, 1, "v2").then((cellData) => {
expect(cellData).to.be.equal(
"Adding Title Suggestion via script-updating title",
);
@ -370,19 +370,19 @@ describe("AForce - Community Issues page validations", function () {
it("10. Validate Deleting the newly created issue", () => {
agHelper.AssertElementAbsence(locator._widgetInDeployed("tabswidget"));
table.SelectTableRow(0);
table.SelectTableRow(0, 0, true, "v2");
agHelper.AssertElementVisible(locator._widgetInDeployed("tabswidget"));
agHelper.Sleep();
cy.get(table._trashIcon).closest("div").click({ force: true });
agHelper.WaitUntilEleDisappear(locator._widgetInDeployed("tabswidget"));
agHelper.AssertElementAbsence(locator._widgetInDeployed("tabswidget"));
table.WaitForTableEmpty();
table.WaitForTableEmpty("v2");
//2nd search is not working, hence commenting below
// cy.xpath(table._searchBoxCross).click()
// table.SearchTable('Troubleshooting')
// table.WaitUntilTableLoad()
// table.ReadTableRowColumnData(0, 1).then((cellData) => {
// table.WaitUntilTableLoad(0,0,"v2")
// table.ReadTableRowColumnData(0, 1, "v2").then((cellData) => {
// expect(cellData).not.to.be.equal("Adding Title Suggestion via script-updating title");
// });
});

View File

@ -86,10 +86,10 @@ describe("Import, Export and Fork application and validate data binding", functi
const url = anchor.prop("href");
cy.request(url).then(({ body, headers }) => {
expect(headers).to.have.property("content-type", "application/json");
expect(headers).to.have.property(
"content-disposition",
`attachment; filename*=UTF-8''${appName}.json`,
);
expect(headers)
.to.have.property("content-disposition")
.that.includes("attachment;")
.and.includes(`filename*=UTF-8''${appName}.json`);
cy.writeFile("cypress/fixtures/exportedApp.json", body, "utf-8");
cy.generateUUID().then((uid) => {
workspaceId = uid;

View File

@ -338,9 +338,9 @@ describe("Autocomplete tests", () => {
// Same check in JSObject1
_.entityExplorer.SelectEntityByName("JSObject1", "Queries/JS");
_.agHelper.Sleep();
_.agHelper.GetNClick(_.jsEditor._lineinJsEditor(5));
_.agHelper.TypeText(_.locators._codeMirrorTextArea, "JSObject2");
_.agHelper.Sleep();
_.agHelper.TypeText(_.locators._codeMirrorTextArea, ".");
_.agHelper.GetNAssertElementText(

View File

@ -4,6 +4,7 @@ const {
AggregateHelper: agHelper,
CommonLocators: locator,
EntityExplorer: ee,
JSEditor: jsEditor,
LibraryInstaller: installer,
PropertyPane: propPane,
} = ObjectsRegistry;
@ -109,4 +110,47 @@ describe("Autocomplete bug fixes", function () {
propPane.TypeTextIntoField("Text", "{{UUID.");
agHelper.AssertElementAbsence(locator._hints);
});
it("9. Bug #20449 Cursor should be between parenthesis when function is autocompleted (Property Pane)", function () {
ee.SelectEntityByName("Text1");
propPane.TypeTextIntoField("Text", "{{console.l");
agHelper.GetNClickByContains(locator._hints, "log");
propPane.TypeTextIntoField("Text", '"hello"', false);
// If the cursor was not between parenthesis, the following command will fail
propPane.ValidatePropertyFieldValue("Text", '{{console.log("hello")}}');
});
it("10. Bug #20449 Cursor should be between parenthesis when function is autocompleted (JS Object)", function () {
jsEditor.CreateJSObject(
`export default {
myFun1: () => {
},
}`,
{
paste: true,
completeReplace: true,
toRun: false,
shouldCreateNewJSObj: true,
prettify: false,
},
);
agHelper.GetNClick(jsEditor._lineinJsEditor(3));
agHelper.TypeText(locator._codeMirrorTextArea, "console.l");
agHelper.GetNClickByContains(locator._hints, "log");
agHelper.TypeText(locator._codeMirrorTextArea, "'hello'");
// If the cursor was not between parenthesis, the following command will fail
agHelper.GetNAssertContains(
jsEditor._lineinJsEditor(3),
"console.log('hello')",
);
});
});

View File

@ -49,4 +49,15 @@ describe("Property Pane Suggestions", () => {
1,
);
});
it("3. Should add Autocomplete Suggestions on Tab press", () => {
EntityExplorer.SelectEntityByName("Button1", "Widgets");
PropertyPane.TypeTextIntoField("Label", "{{");
AggregateHelper.GetNAssertElementText(CommonLocators._hints, "appsmith");
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
cy.get("body").tab();
PropertyPane.ValidatePropertyFieldValue("Label", "{{appsmith}}");
});
});

View File

@ -0,0 +1,43 @@
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
const dataSources = ObjectsRegistry.DataSources,
agHelper = ObjectsRegistry.AggregateHelper,
ee = ObjectsRegistry.EntityExplorer;
describe("Bug 21734: On exiting from the Datasources page without saving changes, an error is thrown and the app becomes unresponsive.", function () {
it("1. Navigating from intermediary datasource to new page", function () {
dataSources.NavigateToDSCreateNew();
dataSources.CreatePlugIn("Google Sheets");
ee.AddNewPage();
agHelper.AssertContains(
"DON'T SAVE",
"exist",
dataSources._datasourceModalDoNotSave,
);
cy.get(dataSources._datasourceModalDoNotSave).click();
ee.SelectEntityByName("Page1");
agHelper.ValidateURL("page1");
ee.SelectEntityByName("Page2");
agHelper.ValidateURL("page2");
});
it("2. Navigating from intermediary datasource to an existing page", function () {
dataSources.NavigateToDSCreateNew();
dataSources.CreatePlugIn("PostgreSQL");
ee.SelectEntityByName("Page1");
agHelper.AssertContains(
"DON'T SAVE",
"exist",
dataSources._datasourceModalDoNotSave,
);
cy.get(dataSources._datasourceModalDoNotSave).click();
agHelper.ValidateURL("page1");
ee.SelectEntityByName("Page2");
agHelper.ValidateURL("page2");
});
});

View File

@ -46,7 +46,12 @@ describe("SSO with Google test functionality", function () {
// assert server is restarting
cy.get(adminSettings.restartNotice).should("be.visible");
// adding wait for server to restart
cy.wait(120000);
cy.waitUntil(() =>
cy
.contains("Google Authentication", { timeout: 180000 })
.should("be.visible"),
);
cy.wait(1000);
cy.waitUntil(() => cy.get(homePage.profileMenu).should("be.visible"));
cy.get(homePage.profileMenu).click();
cy.get(homePage.signOutIcon).click();
@ -83,7 +88,12 @@ describe("SSO with Google test functionality", function () {
// assert server is restarting
cy.get(adminSettings.restartNotice).should("be.visible");
// adding wait for server to restart
cy.wait(120000);
cy.waitUntil(() =>
cy
.contains("Google Authentication", { timeout: 180000 })
.should("be.visible"),
);
cy.wait(1000);
cy.waitUntil(() => cy.get(homePage.profileMenu).should("be.visible"));
cy.get(homePage.profileMenu).click();
cy.get(homePage.signOutIcon).click();

View File

@ -0,0 +1,105 @@
const commonlocators = require("../../../../locators/commonlocators.json");
let widgets = [
"codescannerwidget",
"listwidgetv2",
"tablewidgetv2",
"tabswidget",
];
let height = {
codescannerwidget: 0,
listwidgetv2: 0,
tablewidgetv2: 0,
tabswidget: 0,
};
let width = {
codescannerwidget: 0,
listwidgetv2: 0,
tablewidgetv2: 0,
tabswidget: 0,
};
describe("Validating Mobile Views for Auto Fill Widgets", function () {
it("To capture the height and width of various autofill / Hug widgets in webview", function () {
cy.get(commonlocators.autoConvert).click({
force: true,
});
cy.get(commonlocators.convert).click({
force: true,
});
cy.get(commonlocators.refreshApp).click({
force: true,
});
cy.wait(2000);
cy.dragAndDropToCanvas("codescannerwidget", { x: 100, y: 200 });
cy.dragAndDropToCanvas("listwidgetv2", { x: 620, y: 820 });
cy.dragAndDropToCanvas("tablewidgetv2", { x: 620, y: 820 });
cy.dragAndDropToCanvas("tabswidget", { x: 770, y: 770 });
cy.wait(2000);
cy.PublishtheApp();
cy.wait(2000);
for (let i = 0; i < widgets.length; i++) {
cy.get(".t--widget-".concat(widgets[i]))
.invoke("css", "height")
.then((newheight) => {
height[widgets[i]] = newheight;
cy.log(height[widgets[i]]);
});
cy.get(".t--widget-".concat(widgets[i]))
.invoke("css", "width")
.then((newwidth) => {
width[widgets[i]] = newwidth;
cy.log(width[widgets[i]]);
});
}
});
let phones = [
[390, 844],
[360, 780],
];
phones.forEach((phone) => {
it(`${phone} port execution For Auto Fill Widgets`, function () {
if (Cypress._.isArray(phone)) {
cy.viewport(phone[0], phone[1]);
} else {
cy.viewport(phone);
}
cy.wait(2000);
cy.get(".t--widget-codescannerwidget")
.invoke("css", "height")
.then((newheight) => {
expect(height[widgets[0]]).to.equal(newheight);
});
cy.get(".t--widget-codescannerwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[0]]).to.not.equal(newwidth);
});
cy.get(".t--widget-listwidgetv2")
.invoke("css", "height")
.then((newheight) => {
expect(height[widgets[1]]).to.equal(newheight);
});
cy.get(".t--widget-listwidgetv2")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[1]]).to.not.equal(newwidth);
});
cy.get(".t--widget-tablewidgetv2")
.invoke("css", "height")
.then((newheight) => {
expect(height[widgets[2]]).to.equal(newheight);
});
cy.get(".t--widget-tablewidgetv2")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[2]]).to.not.equal(newwidth);
});
cy.get(".t--widget-tabswidget")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[3]]).to.not.equal(newwidth);
});
});
});
});

View File

@ -0,0 +1,189 @@
const commonlocators = require("../../../../locators/commonlocators.json");
let widgets = [
"switchwidget",
"currencyinputwidget",
"audiowidget",
"checkboxwidget",
"selectwidget",
"radiogroupwidget",
"datepickerwidget2",
"phoneinputwidget",
"categorysliderwidget",
];
let height = {
switchwidget: 0,
currencyinputwidget: 0,
audiowidget: 0,
checkboxwidget: 0,
selectwidget: 0,
radiogroupwidget: 0,
datepickerwidget2: 0,
phoneinputwidget: 0,
categorysliderwidget: 0,
};
let width = {
switchwidget: 0,
currencyinputwidget: 0,
audiowidget: 0,
checkboxwidget: 0,
selectwidget: 0,
radiogroupwidget: 0,
datepickerwidget2: 0,
phoneinputwidget: 0,
categorysliderwidget: 0,
};
describe("Validating Mobile Views for Auto Fill Widgets", function () {
it("To capture the height and width of various autofill / Hug widgets in webview", function () {
cy.get(commonlocators.autoConvert).click({
force: true,
});
cy.get(commonlocators.convert).click({
force: true,
});
cy.get(commonlocators.refreshApp).click({
force: true,
});
cy.wait(2000);
cy.dragAndDropToCanvas("switchwidget", { x: 100, y: 200 });
cy.dragAndDropToCanvas("currencyinputwidget", { x: 110, y: 210 });
cy.dragAndDropToCanvas("audiowidget", { x: 250, y: 300 });
cy.dragAndDropToCanvas("selectwidget", { x: 560, y: 560 });
cy.dragAndDropToCanvas("checkboxwidget", { x: 770, y: 770 });
cy.dragAndDropToCanvas("radiogroupwidget", { x: 770, y: 770 });
cy.dragAndDropToCanvas("datepickerwidget2", { x: 770, y: 970 });
cy.dragAndDropToCanvas("phoneinputwidget", { x: 660, y: 810 });
cy.dragAndDropToCanvas("categorysliderwidget", { x: 620, y: 810 });
cy.wait(5000); //for dsl to settle
cy.PublishtheApp();
cy.wait(2000);
for (let i = 0; i < widgets.length; i++) {
cy.get(".t--widget-".concat(widgets[i]))
.invoke("css", "height")
.then((newheight) => {
height[widgets[i]] = newheight;
cy.log(height[widgets[i]]);
});
cy.get(".t--widget-".concat(widgets[i]))
.invoke("css", "width")
.then((newwidth) => {
width[widgets[i]] = newwidth;
cy.log(width[widgets[i]]);
});
}
});
let phones = [
[390, 844],
[360, 780],
];
phones.forEach((phone) => {
it(`${phone} port execution For Auto Fill Widgets`, function () {
if (Cypress._.isArray(phone)) {
cy.viewport(phone[0], phone[1]);
} else {
cy.viewport(phone);
}
cy.wait(2000);
cy.get(".t--widget-switchwidget")
.invoke("css", "height")
.then((newheight) => {
expect(height[widgets[0]]).to.equal(newheight);
});
cy.get(".t--widget-switchwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[0]]).to.not.equal(newwidth);
});
cy.get(".t--widget-currencyinputwidget")
.invoke("css", "height")
.then((newheight) => {
expect(height[widgets[1]]).to.equal(newheight);
});
cy.get(".t--widget-currencyinputwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[1]]).to.not.equal(newwidth);
});
cy.get(".t--widget-audiowidget")
.invoke("css", "height")
.then((newheight) => {
expect(height[widgets[2]]).to.equal(newheight);
});
cy.get(".t--widget-audiowidget")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[2]]).to.not.equal(newwidth);
});
cy.get(".t--widget-selectwidget")
.invoke("css", "height")
.then((newheight) => {
expect(parseFloat(height[widgets[3]])).to.not.equal(
parseFloat(newheight),
);
});
cy.get(".t--widget-selectwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(parseFloat(width[widgets[3]])).to.not.equal(
parseFloat(newwidth),
);
});
cy.get(".t--widget-checkboxwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(parseFloat(width[widgets[4]])).to.not.equal(
parseFloat(newwidth),
);
});
cy.get(".t--widget-radiogroupwidget")
.invoke("css", "height")
.then((newheight) => {
expect(parseFloat(height[widgets[5]])).to.equal(
parseFloat(newheight),
);
});
cy.get(".t--widget-radiogroupwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(parseFloat(width[widgets[5]])).to.not.equal(
parseFloat(newwidth),
);
});
cy.get(".t--widget-datepickerwidget2")
.scrollIntoView()
.invoke("css", "width")
.then((newwidth) => {
expect(parseFloat(width[widgets[6]])).to.be.at.least(
parseFloat(newwidth),
);
});
cy.get(".t--widget-phoneinputwidget")
.invoke("css", "height")
.then((newheight) => {
expect(parseFloat(height[widgets[7]])).to.equal(
parseFloat(newheight),
);
});
cy.get(".t--widget-phoneinputwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(parseFloat(width[widgets[7]])).to.not.equal(
parseFloat(newwidth),
);
});
cy.get(".t--widget-categorysliderwidget")
.invoke("css", "height")
.then((newheight) => {
expect(parseFloat(height[widgets[8]])).to.equal(
parseFloat(newheight),
);
});
cy.get(".t--widget-categorysliderwidget")
.invoke("css", "width")
.then((newwidth) => {
expect(width[widgets[8]]).to.not.equal(parseFloat(newwidth));
});
});
});
});

View File

@ -0,0 +1,67 @@
const commonlocators = require("../../../../locators/commonlocators.json");
let theight;
let twidth;
describe("Validating Mobile View related usecases for Autoscroll", function () {
it("Capture the height/width of autofill widgets in webview", function () {
cy.get(commonlocators.autoConvert).click({
force: true,
});
cy.get(commonlocators.convert).click({
force: true,
});
cy.get(commonlocators.refreshApp).click({
force: true,
});
cy.wait(2000);
cy.dragAndDropToCanvas("listwidgetv2", { x: 100, y: 200 });
cy.dragAndDropToCanvas("containerwidget", { x: 620, y: 820 });
for (let i = 0; i < 10; i++) {
cy.dragAndDropToCanvas("inputwidgetv2", { x: 450, y: 530 });
}
cy.get(".t--widget-inputwidgetv2").first().should("be.visible");
cy.PublishtheApp();
cy.wait(2000);
cy.get(".t--widget-inputwidgetv2")
.invoke("css", "height")
.then((newheight) => {
theight = newheight;
});
cy.get(".t--widget-inputwidgetv2")
.invoke("css", "width")
.then((newwidth) => {
twidth = newwidth;
});
});
let phones = [
[390, 844],
[360, 780],
];
phones.forEach((phone) => {
it(`${phone} port execution for autoscroll`, function () {
if (Cypress._.isArray(phone)) {
cy.viewport(phone[0], phone[1]);
} else {
cy.viewport(phone);
}
cy.wait(2000);
for (let i = 0; i < 10; i++) {
cy.get(".t--widget-inputwidgetv2")
.eq(i)
.scrollIntoView()
.invoke("css", "height")
.then((newheight) => {
expect(theight).to.equal(newheight);
});
cy.get(".t--widget-inputwidgetv2")
.eq(i)
.scrollIntoView()
.invoke("css", "width")
.then((newwidth) => {
expect(twidth).to.not.equal(newwidth);
});
}
});
});
});

View File

@ -1,37 +1,23 @@
const dsl = require("../../../../fixtures/inputWidgetMobileDsl.json");
const commonlocators = require("../../../../locators/commonlocators.json");
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
const agHelper = ObjectsRegistry.AggregateHelper;
let theight;
let twidth;
describe("Validating Mobile Views", function () {
afterEach(() => {
agHelper.SaveLocalStorageCache();
});
beforeEach(() => {
agHelper.RestoreLocalStorageCache();
});
it("Validate change with height width for widgets", function () {
cy.wait(5000);
describe("Validating Mobile Views for Fill Widget", function () {
it("Validate change with height width for fill widget - Input widget", function () {
cy.get(commonlocators.autoConvert).click({
force: true,
});
cy.wait(2000);
cy.get(commonlocators.convert).click({
force: true,
});
cy.wait(2000);
cy.get(commonlocators.refreshApp).click({
force: true,
});
cy.wait(2000);
cy.addDsl(dsl);
cy.wait(5000); //for dsl to settle
//cy.openPropertyPane("containerwidget");
cy.dragAndDropToCanvas("inputwidgetv2", { x: 100, y: 200 });
cy.dragAndDropToCanvas("inputwidgetv2", { x: 10, y: 20 });
cy.PublishtheApp();
cy.wait(2000);
cy.get(".t--widget-inputwidgetv2").first().should("be.visible");
cy.get(".t--widget-inputwidgetv2").last().should("be.visible");
cy.get(".t--widget-inputwidgetv2")
.invoke("css", "height")
.then((newheight) => {
@ -43,10 +29,10 @@ describe("Validating Mobile Views", function () {
twidth = newwidth;
});
});
//Added viewports of iphone14 and samsung galaxy s22 for testing purpose
let phones = ["iphone-4", "samsung-s10", [390, 844], [360, 780]];
phones.forEach((phone) => {
it(`${phone} port execution`, function () {
it(`${phone} port execution for fill widget - input widget`, function () {
if (Cypress._.isArray(phone)) {
cy.viewport(phone[0], phone[1]);
} else {

View File

@ -1,40 +1,23 @@
const dsl = require("../../../../fixtures/ImageHugWidgetDsl.json");
const commonlocators = require("../../../../locators/commonlocators.json");
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
const agHelper = ObjectsRegistry.AggregateHelper;
describe("Validating Mobile Views", function () {
afterEach(() => {
agHelper.SaveLocalStorageCache();
});
beforeEach(() => {
agHelper.RestoreLocalStorageCache();
});
it("Validate change with height width for widgets", function () {
cy.wait(5000);
describe("Validating Mobile Views for Hug Widget", function () {
it("Validate change with height width for hug widget - image widget", function () {
cy.get(commonlocators.autoConvert).click({
force: true,
});
cy.wait(2000);
cy.get(commonlocators.convert).click({
force: true,
});
cy.wait(2000);
cy.get(commonlocators.refreshApp).click({
force: true,
});
cy.wait(2000);
cy.addDsl(dsl);
cy.wait(5000); //for dsl to settle
cy.dragAndDropToCanvas("imagewidget", { x: 300, y: 600 });
cy.PublishtheApp();
cy.wait(2000);
cy.get(".t--widget-imagewidget").first().should("be.visible");
});
//Added viewports of iphone14 and samsung galaxy s22 for testing purpose
let phones = ["iphone-4", "samsung-s10", [390, 844], [360, 780]];
phones.forEach((phone) => {
it(`${phone} port execution`, function () {
it(`${phone} port execution for hug widget -image widget `, function () {
if (Cypress._.isArray(phone)) {
cy.viewport(phone[0], phone[1]);
} else {

View File

@ -1,5 +1,5 @@
const OnboardingLocator = require("../../../../locators/FirstTimeUserOnboarding.json");
const _ = require("lodash");
import * as _ from "../../../../support/Objects/ObjectsCore";
describe("FirstTimeUserOnboarding", function () {
beforeEach(() => {
@ -67,7 +67,7 @@ describe("FirstTimeUserOnboarding", function () {
let open;
cy.window().then((window) => {
open = window.open;
window.open = _.noop;
window.open = Cypress._.noop;
});
cy.get(OnboardingLocator.checklistDeployBtn).should("be.visible");
cy.get(OnboardingLocator.checklistDeployBtn).click();
@ -162,4 +162,25 @@ describe("FirstTimeUserOnboarding", function () {
cy.get(OnboardingLocator.statusbar).should("be.visible");
cy.get(OnboardingLocator.textWidgetName).should("be.visible");
});
it("7. onboarding flow - new apps created should start with signposting", function () {
cy.get(OnboardingLocator.introModalBuild).click();
cy.get(OnboardingLocator.taskDatasourceBtn).should("be.visible");
_.homePage.NavigateToHome();
_.homePage.CreateNewApplication(false);
cy.get(OnboardingLocator.taskDatasourceBtn).should("be.visible");
});
it("8. onboarding flow - once signposting is completed new apps won't start with signposting", function () {
_.onboarding.completeSignposting();
_.homePage.NavigateToHome();
_.agHelper.RefreshPage();
_.homePage.CreateNewApplication(false);
_.agHelper.AssertElementExist(_.locators._dropHere);
_.agHelper.AssertElementAbsence(OnboardingLocator.statusbar);
});
});

View File

@ -32,10 +32,10 @@ describe("Export application as a JSON file", function () {
const url = anchor.prop("href");
cy.request(url).then(({ headers }) => {
expect(headers).to.have.property("content-type", "application/json");
expect(headers).to.have.property(
"content-disposition",
`attachment; filename*=UTF-8''${appname}.json`,
);
expect(headers)
.to.have.property("content-disposition")
.that.includes("attachment;")
.and.includes(`filename*=UTF-8''${appname}.json`);
});
});
cy.LogOut();

View File

@ -236,7 +236,6 @@ describe("Debugger logs", function () {
prettify: false,
},
);
agHelper.WaitUntilAllToastsDisappear();
// Edit JSObject and verify no logs are visible
jsEditor.EditJSObj(`export default {
@ -285,7 +284,6 @@ describe("Debugger logs", function () {
shouldCreateNewJSObj: true,
},
);
agHelper.WaitUntilAllToastsDisappear();
cy.get("@jsObjName").then((jsObjName) => {
agHelper.Sleep(2000);
@ -330,7 +328,6 @@ describe("Debugger logs", function () {
shouldCreateNewJSObj: true,
},
);
agHelper.WaitUntilAllToastsDisappear();
agHelper.GetNClick(jsEditor._runButton);
agHelper.GetNClick(jsEditor._logsTab);
debuggerHelper.DoesConsoleLogExist(`${logString} Started`);
@ -355,7 +352,6 @@ describe("Debugger logs", function () {
shouldCreateNewJSObj: false,
},
);
agHelper.WaitUntilAllToastsDisappear();
agHelper.GetNClick(jsEditor._runButton);
agHelper.GetNClick(jsEditor._logsTab);
debuggerHelper.DoesConsoleLogExist(`Parent ${logString}`);
@ -383,7 +379,6 @@ describe("Debugger logs", function () {
shouldCreateNewJSObj: true,
},
);
agHelper.WaitUntilAllToastsDisappear();
agHelper.GetNClick(jsEditor._runButton);
agHelper.GetNClick(jsEditor._logsTab);
debuggerHelper.DoesConsoleLogExist(`${logString}`);

View File

@ -13,12 +13,11 @@ describe("Omnibar functionality test cases", () => {
cy.addDsl(dsl);
});
it("1. Bug #15104 The Data is not displayed in Omnibar after clicking on learn more link from property pane", function () {
it("1. Docs tab opens after clicking on learn more link from property pane", function () {
cy.dragAndDropToCanvas("audiowidget", { x: 300, y: 500 });
cy.xpath('//span[text()="Learn more"]').click();
cy.get(locators._omnibarDescription).scrollTo("top");
cy.get(omnibar.openDocumentationLink);
cy.get("body").click(0, 0);
ObjectsRegistry.AggregateHelper.AssertNewTabOpened(() => {
cy.xpath('//span[text()="Learn more"]').click();
});
});
it("2.Verify omnibar is present across all pages and validate its fields", function () {

View File

@ -38,6 +38,7 @@ describe("Fork a template to the current app", () => {
.scrollIntoView()
.wait(500)
.click();
cy.get(template.templateViewForkButton).first().click();
cy.waitUntil(() => cy.xpath("//span[text()='Setting up the template']"), {
errorMsg: "Setting Templates did not finish even after 75 seconds",
timeout: 950000,

View File

@ -73,4 +73,22 @@ describe("Fork a template to the current app from new page popover", () => {
"template added successfully",
);
});
it("Fork template button should take user to 'select pages from template' page", () => {
_.agHelper.RefreshPage();
cy.AddPageFromTemplate();
cy.get(_.templates.locators._forkApp).first().click();
cy.get(template.templateViewForkButton).should("be.visible");
});
it("Similar templates add icon should take user to 'select pages from template' page", () => {
_.agHelper.RefreshPage();
cy.AddPageFromTemplate();
// We are currentlyon on templates list page
cy.get(_.templates.locators._forkApp).first().click();
// Here we are on template detail page, with similar templates at the bottom
cy.get(_.templates.locators._forkApp).first().click();
cy.get(template.templateViewForkButton).should("be.visible");
});
});

View File

@ -224,7 +224,7 @@ myFun2: async () => {
agHelper.GetNClick("[name='expand-more']", 0, true, 100);
agHelper.ContainsNClick("myFun2");
cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify2");
agHelper.AssertContains("ran successfully");
agHelper.AssertContains("ran successfully", "not.exist");
});
it("3. TC 1863 : JSEditor validation for Prettify Code with lint errors, triggered by keyboard shortcut", () => {
@ -332,7 +332,7 @@ myFun2: async () => {
agHelper.GetNClick("[name='expand-more']", 0, true, 100);
agHelper.ContainsNClick("myFun2");
cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify4_1");
agHelper.AssertContains("ran successfully");
agHelper.AssertContains("ran successfully", "not.exist");
});
it("5. TC 1862 - JSEditor validation for goLineStartSmart with no errors, triggered by keyboard shortcut", () => {

View File

@ -256,6 +256,8 @@ describe("Input widget V2 - ", () => {
expected: "test@appsmith.com:test@appsmith.com:true",
},
].forEach(({ expected, input }) => enterAndTest(input, expected));
validateAutocompleteAttribute();
});
it("6. Validate DataType - EMAIL can be entered into Input widget", () => {
@ -325,6 +327,8 @@ describe("Input widget V2 - ", () => {
expected: "test@appsmith.com:test@appsmith.com:true",
},
].forEach(({ expected, input }) => enterAndTest(input, expected));
validateAutocompleteAttribute();
});
it("7. Validating other properties - Input validity with #valid", () => {
@ -441,4 +445,40 @@ describe("Input widget V2 - ", () => {
}
cy.get(".t--widget-textwidget").should("contain", expected);
}
function validateAutocompleteAttribute() {
//validate autocomplete behaviour for email and password
cy.openPropertyPane("textwidget");
cy.openPropertyPane(widgetName);
//check if autofill toggle option is present and is checked by default
cy.get(".t--property-control-allowautofill input").should("be.checked");
//check if autocomplete attribute is not present in the text widget when autofill is enabled
cy.get(widgetInput).should("not.have.attr", "autocomplete");
//toggle off autofill
cy.get(".t--property-control-allowautofill input").click({ force: true });
cy.get(".t--property-control-allowautofill input").should("not.be.checked");
//autocomplete should now be present in the text widget
cy.get(widgetInput).should("have.attr", "autocomplete", "off");
//select a non email or password option
cy.selectDropdownValue(".t--property-control-datatype", "text");
//autofill toggle should not be present as this restores autofill to be enabled
cy.get(".t--property-control-allowautofill input").should("not.exist");
//autocomplete attribute should not be present in the text widget
cy.get(widgetInput).should("not.have.attr", "autocomplete");
}
function enterAndTest(text, expected) {
cy.get(`.t--widget-${widgetName} input`).clear();
cy.wait(300);
if (text) {
cy.get(`.t--widget-${widgetName} input`)
.click({ force: true })
.type(text);
}
cy.get(".t--widget-textwidget").should("contain", expected);
}
});

View File

@ -87,13 +87,14 @@ describe("Text Field Property Control", () => {
cy.get(`${fieldPrefix}-name`).should("exist");
});
it("8. disables field when disabled switched on", () => {
it("8. disables field when disabled switched on and when autofill is disabled we should see the autofill attribute in the input field", () => {
cy.togglebar(`.t--property-control-disabled input`);
cy.get(`${fieldPrefix}-name input`).each(($el) => {
cy.wrap($el).should("have.attr", "disabled");
});
cy.togglebarDisable(`.t--property-control-disabled input`);
validateAutocompleteAttributeInJSONForm();
});
it("9. throws error when REGEX does not match the input value", () => {
@ -326,3 +327,31 @@ describe("Text Field Property Control", () => {
cy.get(`${fieldPrefix}-radio`).should("exist");
});
});
function validateAutocompleteAttributeInJSONForm() {
//select password input fiel
cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Password Input");
//check if autofill toggle option is present and is checked by default
cy.get(".t--property-control-allowautofill input").should("be.checked");
//check if autocomplete attribute is not present in the text widget when autofill is enabled
cy.get(`${fieldPrefix}-name input`).should("not.have.attr", "autocomplete");
//toggle off autofill
cy.get(".t--property-control-allowautofill input").click({ force: true });
cy.get(".t--property-control-allowautofill input").should("not.be.checked");
//autocomplete should now be present in the text widget
cy.get(`${fieldPrefix}-name input`).should(
"have.attr",
"autocomplete",
"off",
);
//select a non email or password option
cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/);
//autofill toggle should not be present as this restores autofill to be enabled
cy.get(".t--property-control-allowautofill input").should("not.exist");
//autocomplete attribute should not be present in the text widget
cy.get(`${fieldPrefix}-name input`).should("not.have.attr", "autocomplete");
}

View File

@ -4,6 +4,31 @@ describe("List widget v2 Evaluated Popup", () => {
x: 300,
y: 300,
});
[["{{null}}", "[]"]].forEach(([input, expected]) => {
cy.updateCodeInput(".t--property-control-items", input);
cy.wait(500);
cy.validateEvaluatedValue(expected);
});
cy.updateCodeInput(
".t--property-control-items",
`{{[{
id: "001",
name: "Blue",
img: "https://assets.appsmith.com/widgets/default.png",
},
{
id: "002",
name: "Green",
img: "https://assets.appsmith.com/widgets/default.png",
},
{
id: "003",
name: "Red",
img: "https://assets.appsmith.com/widgets/default.png",
}]}}`,
);
cy.openPropertyPaneByWidgetName("Text1", "textwidget");
[
@ -12,6 +37,15 @@ describe("List widget v2 Evaluated Popup", () => {
["{{currentItem.name}}_{{currentIndex}}", "Blue_0"],
["{{1000}}", "1000"],
['{{(() => "Text Widget")()}}', "Text Widget"],
["NewLine\n{{currentItem.name}}", "NewLine\nBlue"],
[`\{{currentItem.name}}`, `\Blue`],
[
`{{
(function(){return true;})
()}}
`,
"true",
],
].forEach(([input, expected]) => {
cy.updateCodeInput(".t--property-control-text", input);
cy.wait(500);

View File

@ -1,8 +1,7 @@
const dsl = require("../../../../../fixtures/Listv2/MetaHydrationDSL.json");
const commonlocators = require("../../../../../locators/commonlocators.json");
const datasource = require("../../../../../locators/DatasourcesEditor.json");
const queryLocators = require("../../../../../locators/QueryEditor.json");
const publishPage = require("../../../../../locators/publishWidgetspage.json");
import * as _ from "../../../../../support/Objects/ObjectsCore";
import { ObjectsRegistry } from "../../../../../support/Objects/Registry";
@ -74,25 +73,7 @@ function testJsontextClear(endp) {
.type(`{${modifierKey}}{del}`, { force: true });
}
function verifyMultiDropdownValuesCount(count, page = 1) {
cy.get(".rc-select-selection-overflow").then(($ele) => {
if (
$ele.find(".rc-select-selection-overflow-item .remove-icon").length ==
count
) {
cy.reload();
if (page == 2) {
// Go to next page
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
}
}
});
}
// Skipping this test due to regression, issue id to track this regression https://github.com/appsmithorg/appsmith/issues/22534
describe.skip("List widget v2 - meta hydration tests", () => {
describe("List widget v2 - meta hydration tests", () => {
before(() => {
agHelper.AddDsl(dsl);
});
@ -105,51 +86,12 @@ describe.skip("List widget v2 - meta hydration tests", () => {
});
it("1. setup serverside data", () => {
cy.wait(1000);
cy.NavigateToDatasourceEditor();
// // Click on sample(mock) user database.
// cy.get(datasource.mockUserDatabase).click();
// Choose the first data source which consists of users keyword & Click on the "New Query +"" button
// Choose the first data source which consists of users keyword & Click on the "New Query +"" button
cy.get(`${datasource.datasourceCard}`)
.filter(":contains('Users')")
.first()
.within(() => {
cy.get(`${datasource.createQuery}`).click({ force: true });
});
// Click the editing field
cy.get(".t--action-name-edit-field").click({ force: true });
// Click the editing field
cy.get(queryLocators.queryNameField).type("Query1");
// switching off Use Prepared Statement toggle
cy.get(queryLocators.switch).last().click({ force: true });
//.1: Click on Write query area
cy.get(queryLocators.templateMenu).click();
cy.get(queryLocators.query).click({
force: true,
});
// writing query to get the schema
cy.get(".CodeMirror textarea")
.first()
.focus()
.type(
"SELECT * FROM users OFFSET {{List1.pageNo * List1.pageSize}} LIMIT {{List1.pageSize}};",
{
force: true,
parseSpecialCharSequences: false,
},
);
cy.WaitAutoSave();
cy.runQuery();
cy.get('.t--entity-name:contains("Page1")').click({ force: true });
cy.createAndFillApi(
"http://host.docker.internal:5001/v1/mock-api?records=20&page={{List1.pageNo}}&size={{List1.pageSize}}",
"",
);
cy.RunAPI();
cy.SearchEntityandOpen("List1");
cy.wait(1000);
@ -157,18 +99,17 @@ describe.skip("List widget v2 - meta hydration tests", () => {
testJsontextClear("items");
cy.testJsontext("items", "{{Query1.data}}");
cy.testJsontext("items", "{{Api1.data}}");
cy.togglebar(commonlocators.serverSidePaginationCheckbox);
cy.get(toggleJSButton("onpagechange")).click({ force: true });
cy.testJsontext("onpagechange", "{{Query1.run()}}");
cy.testJsontext("onpagechange", "{{Api1.run()}}");
cy.get(`${widgetSelector("List1")} ${containerWidgetSelector}`).should(
"have.length",
3,
);
verifyMultiDropdownValuesCount(6);
});
it("2. using server side data", () => {
@ -215,7 +156,6 @@ describe.skip("List widget v2 - meta hydration tests", () => {
);
});
verifyMultiDropdownValuesCount(6, 2);
// SecondPage
// First Row
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
@ -251,15 +191,15 @@ describe.skip("List widget v2 - meta hydration tests", () => {
.should("have.length", 3),
);
cy.get(`${widgetSelector("List1")} ${containerWidgetSelector}`)
.eq(0)
.within(() => {
cy.waitUntil(() =>
cy
.get(".rc-select-selection-overflow-item .remove-icon")
.should("exist"),
);
});
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .rc-select-selection-overflow-item .remove-icon`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
@ -311,15 +251,15 @@ describe.skip("List widget v2 - meta hydration tests", () => {
.should("have.length", 3),
);
cy.get(`${widgetSelector("List1")} ${containerWidgetSelector}`)
.eq(0)
.within(() => {
cy.waitUntil(() =>
cy
.get(".rc-select-selection-overflow-item .remove-icon")
.should("exist"),
);
});
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .rc-select-selection-overflow-item .remove-icon`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
@ -436,15 +376,15 @@ describe.skip("List widget v2 - meta hydration tests", () => {
.should("have.length", 3),
);
cy.get(`${widgetSelector("List1")} ${containerWidgetSelector}`)
.eq(0)
.within(() => {
cy.waitUntil(() =>
cy
.get(".rc-select-selection-overflow-item .remove-icon")
.should("exist"),
);
});
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .rc-select-selection-overflow-item .remove-icon`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
@ -496,15 +436,15 @@ describe.skip("List widget v2 - meta hydration tests", () => {
.should("have.length", 3),
);
cy.get(`${widgetSelector("List1")} ${containerWidgetSelector}`)
.eq(0)
.within(() => {
cy.waitUntil(() =>
cy
.get(".rc-select-selection-overflow-item .remove-icon")
.should("exist"),
);
});
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .rc-select-selection-overflow-item .remove-icon`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>

View File

@ -28,7 +28,7 @@ describe("Dropdown Widget Functionality", function () {
.find(widgetLocators.menuButton)
.invoke("outerWidth")
.then((width) => {
expect(parseInt(width)).to.equal(146);
expect(parseInt(width)).to.equal(147);
});
cy.get(formWidgetsPage.menuButtonWidget)
.find(widgetLocators.menuButton)
@ -40,7 +40,7 @@ describe("Dropdown Widget Functionality", function () {
cy.get(".menu-button-popover")
.invoke("outerWidth")
.then((width) => {
expect(parseInt(width)).to.equal(146);
expect(parseInt(width)).to.equal(147);
});
// MultiSelect

View File

@ -140,7 +140,12 @@ describe("Tab widget test", function () {
cy.get(Layoutpage.tabWidget)
.contains("Tab3-for-testing-scroll-navigation-controls")
.should("have.class", "is-selected");
cy.get(Layoutpage.tabDelete).eq(3).click({ force: true });
cy.xpath(
Layoutpage.deleteTab.replace(
"tabName",
"Tab3-for-testing-scroll-navigation-controls",
),
).click({ force: true });
cy.get(Layoutpage.tabWidget)
.contains("Tab 2")
.should("have.class", "is-selected");

View File

@ -1,26 +1,22 @@
const explorer = require("../../../../../locators/explorerlocators.json");
import homePage from "../../../../../locators/HomePage";
const publish = require("../../../../../locators/publishWidgetspage.json");
const dsl = require("../../../../../fixtures/swtchTableDsl.json");
const explorer = require("../../../../../locators/explorerlocators.json");
const dsl = require("../../../../../fixtures/tableNewDsl.json");
describe("Table Widget", function () {
before(() => {
cy.addDsl(dsl);
});
it("1. Table Widget Functionality To Check with changing schema of tabledata", () => {
let jsContext = `{{Switch1.isSwitchedOn?[{name: "joe"}]:[{employee_name: "john"}];}}`;
cy.NavigateToHome();
cy.get(homePage.createNew).first().click({ force: true });
cy.wait("@createNewApplication").should(
"have.nested.property",
"response.body.responseMeta.status",
201,
);
cy.addDsl(dsl);
cy.wait(5000);
cy.get(explorer.addWidget).click();
cy.dragAndDropToCanvas("switchwidget", { x: 200, y: 200 });
cy.wait(2000);
cy.openPropertyPane("tablewidget");
cy.get(".t--property-control-tabledata").then(($el) => {
cy.updateCodeInput($el, jsContext);
});
cy.PublishtheApp();
cy.wait(30000);
cy.getTableDataSelector("0", "0").then((element) => {
cy.get(element).should("be.visible");
});
@ -45,9 +41,7 @@ describe("Table Widget", function () {
cy.readTabledataPublish("0", "0").then((value) => {
expect(value).to.be.equal("joe");
});
cy.get(publish.backToEditor).click().wait(1000);
cy.wait(30000);
cy.CheckAndUnfoldEntityItem("Widgets");
cy.actionContextMenuByEntityName("Switch1");
cy.actionContextMenuByEntityName("Table1");

View File

@ -193,6 +193,7 @@ describe("Table widget Add new row feature's", () => {
describe("Validation flow", () => {
before(() => {
cy.startServerAndRoutes();
agHelper.RestoreLocalStorageCache();
cy.addDsl(dsl);
});
@ -350,6 +351,7 @@ describe("Table widget Add new row feature's", () => {
describe("Actions flow (save, discard)", () => {
before(() => {
cy.startServerAndRoutes();
agHelper.RestoreLocalStorageCache();
cy.addDsl(dsl);
});

View File

@ -8,7 +8,7 @@ describe("Label feature", () => {
it("CheckboxGroupWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "checkboxgroupwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='checkboxgroup-container']",
isCompact: true,
labelText: "Name",
@ -21,7 +21,7 @@ describe("Label feature", () => {
it("CurrencyInputWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "currencyinputwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='input-container']",
isCompact: true,
labelText: "Name",
@ -34,7 +34,7 @@ describe("Label feature", () => {
it("DatePickerWidget2 label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "datepickerwidget2",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='datepicker-container']",
isCompact: true,
labelText: "Name",
@ -47,7 +47,7 @@ describe("Label feature", () => {
it("InputWidgetV2 label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "inputwidgetv2",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='input-container']",
isCompact: true,
labelText: "Name",
@ -60,7 +60,7 @@ describe("Label feature", () => {
it("MultiSelectTreeWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "multiselecttreewidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='multitreeselect-container']",
isCompact: true,
labelText: "Name",
@ -73,7 +73,7 @@ describe("Label feature", () => {
it("MultiSelectWidgetV2 label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "multiselectwidgetv2",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='multiselect-container']",
isCompact: true,
labelText: "Name",
@ -86,7 +86,7 @@ describe("Label feature", () => {
it("PhoneInputWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "phoneinputwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='input-container']",
isCompact: true,
labelText: "Name",
@ -99,7 +99,7 @@ describe("Label feature", () => {
it("RadioGroupWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "radiogroupwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='radiogroup-container']",
isCompact: true,
labelText: "Name",
@ -112,7 +112,7 @@ describe("Label feature", () => {
it("RichTextEditorWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "richtexteditorwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='rte-container']",
isCompact: false,
labelText: "Name",
@ -125,7 +125,7 @@ describe("Label feature", () => {
it("SelectWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "selectwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='select-container']",
isCompact: true,
labelText: "Name",
@ -138,7 +138,7 @@ describe("Label feature", () => {
it("SingleSelectTreeWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "singleselecttreewidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='treeselect-container']",
isCompact: true,
labelText: "Name",
@ -151,7 +151,7 @@ describe("Label feature", () => {
it("SwitchGroupWidget label properties: Text, Position, Alignment, Width", () => {
const options = {
widgetName: "switchgroupwidget",
parentColumnSpace: 11.90625,
parentColumnSpace: 11.9375,
containerSelector: "[data-testid='switchgroup-container']",
isCompact: true,
labelText: "Name",

View File

@ -1,20 +1,19 @@
/// <reference types="Cypress" />
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
let HomePage = ObjectsRegistry.HomePage;
import * as _ from "../../../../support/Objects/ObjectsCore";
describe("Leave workspace test spec", function () {
let newWorkspaceName;
it("1. Only admin user can not leave workspace validation", function () {
cy.visit("/applications");
cy.createWorkspace();
cy.wait("@createWorkspace").then((interception) => {
newWorkspaceName = interception.response.body.data.name;
cy.visit("/applications");
_.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
newWorkspaceName = "LeaveWorkspace" + uid;
_.homePage.CreateNewWorkspace(newWorkspaceName);
cy.openWorkspaceOptionsPopup(newWorkspaceName);
// verify leave workspace is visible
cy.contains("Leave Workspace").click();
cy.contains("Are you sure").click();
cy.contains("Leave Workspace").scrollIntoView().click({ force: true });
cy.contains("Are you sure").scrollIntoView().click({ force: true });
cy.wait("@leaveWorkspaceApiCall").then((httpResponse) => {
expect(httpResponse.status).to.equal(400);
});
@ -24,11 +23,11 @@ describe("Leave workspace test spec", function () {
it("2. Bug 17235 & 17987 - Non admin users can only access leave workspace popup menu validation", function () {
cy.visit("/applications");
cy.createWorkspace();
cy.wait("@createWorkspace").then((interception) => {
newWorkspaceName = interception.response.body.data.name;
cy.visit("/applications");
HomePage.InviteUserToWorkspace(
_.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
newWorkspaceName = "LeaveWorkspace" + uid;
_.homePage.CreateNewWorkspace(newWorkspaceName);
_.homePage.InviteUserToWorkspace(
newWorkspaceName,
Cypress.env("TESTUSERNAME1"),
"App Viewer",

View File

@ -56,11 +56,6 @@ describe("Create new workspace and share with a user", function () {
it("3. Enable public access to Application", function () {
cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD"));
cy.wait("@applications").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
cy.SearchApp(appid);
cy.wait("@getPagesForCreateApp").should(
"have.nested.property",
@ -117,11 +112,6 @@ describe("Create new workspace and share with a user", function () {
it("6. login as Owner and disable public access", function () {
cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD"));
cy.wait("@applications").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
cy.SearchApp(appid);
cy.wait("@getPagesForCreateApp").should(
"have.nested.property",

View File

@ -25,10 +25,10 @@ describe("Workspace Import Application", function () {
const url = anchor.prop("href");
cy.request(url).then(({ body, headers }) => {
expect(headers).to.have.property("content-type", "application/json");
expect(headers).to.have.property(
"content-disposition",
`attachment; filename*=UTF-8''${appname}.json`,
);
expect(headers)
.to.have.property("content-disposition")
.that.includes("attachment;")
.and.includes(`filename*=UTF-8''${appname}.json`);
cy.writeFile("cypress/fixtures/exported-app.json", body, "utf-8");
cy.generateUUID().then((uid) => {

View File

@ -15,10 +15,10 @@ describe("API Panel Test Functionality ", function () {
cy.get("body").click(0, 0);
ee.ExpandCollapseEntity("Queries/JS");
ee.ActionContextMenuByEntityName("FirstAPI", "Copy to page", "SecondPage");
// click on learn how link
cy.get(".t--learn-how-apis-link").click();
// this should open in a global search modal
cy.get(commonlocators.globalSearchModal);
ObjectsRegistry.AggregateHelper.AssertNewTabOpened(() => {
// click on learn how link
cy.get(".t--learn-how-apis-link").click();
});
cy.get("body").click(0, 0);
ee.ActionContextMenuByEntityName("FirstAPICopy", "Move to page", "Page1");
cy.wait(2000);

View File

@ -1,5 +1,7 @@
const testdata = require("../../../../fixtures/testdata.json");
import ApiEditor from "../../../../locators/ApiEditor";
import * as _ from "../../../../support/Objects/ObjectsCore";
let APIName;
const testUrl1 =
"http://host.docker.internal:5001/v1/dynamicrecords/generaterecords?records=10";
@ -12,18 +14,28 @@ describe("API Panel Test Functionality ", function () {
cy.log("Login Successful");
cy.NavigateToAPI_Panel();
cy.log("Navigation to API Panel screen successful");
cy.CreateAPI("FirstAPI");
cy.RunAPI();
cy.log("Creation of FirstAPI Action successful");
cy.NavigateToAPI_Panel();
cy.CreateAPI("SecondAPI");
cy.RunAPI();
cy.CheckAndUnfoldEntityItem("Queries/JS");
cy.log("Creation of SecondAPI Action successful");
cy.get(".t--entity-name").contains("FirstAPI");
cy.get(".t--entity-name").contains("SecondAPI");
cy.DeleteAPIFromSideBar();
cy.DeleteAPIFromSideBar();
cy.generateUUID().then((uid) => {
cy.CreateAPI(`FirstAPI_${uid}`);
cy.RunAPI();
cy.log("Creation of FirstAPI Action successful");
cy.NavigateToAPI_Panel();
cy.CreateAPI(`SecondAPI_${uid}`);
cy.RunAPI();
cy.CheckAndUnfoldEntityItem("Queries/JS");
cy.log("Creation of SecondAPI Action successful");
cy.get(".t--entity-name").contains("FirstAPI");
cy.get(".t--entity-name").contains("SecondAPI");
_.entityExplorer.ActionContextMenuByEntityName(
`FirstAPI_${uid}`,
"Delete",
"Are you sure?",
);
_.entityExplorer.ActionContextMenuByEntityName(
`SecondAPI_${uid}`,
"Delete",
"Are you sure?",
);
});
});
it("if suggested widgets section alwas appears for all 3 modes", function () {

View File

@ -8,11 +8,9 @@ describe("Check datasource doc links", function () {
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
_.dataSources.CreateQueryAfterDSSaved();
_.agHelper.GetNClick(_.dataSources._queryDoc);
_.agHelper.AssertElementVisible(_.dataSources._globalSearchModal);
_.agHelper.AssertElementVisible(
_.dataSources._globalSearchInput("PostgreSQL"),
);
_.agHelper.AssertNewTabOpened(() => {
_.agHelper.GetNClick(_.dataSources._queryDoc);
});
});
});
@ -21,11 +19,9 @@ describe("Check datasource doc links", function () {
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
_.dataSources.CreateQueryAfterDSSaved();
_.agHelper.GetNClick(_.dataSources._queryDoc);
_.agHelper.AssertElementVisible(_.dataSources._globalSearchModal);
_.agHelper.AssertElementVisible(
_.dataSources._globalSearchInput("MongoDB"),
);
_.agHelper.AssertNewTabOpened(() => {
_.agHelper.GetNClick(_.dataSources._queryDoc);
});
});
});
@ -34,11 +30,9 @@ describe("Check datasource doc links", function () {
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
_.dataSources.CreateQueryAfterDSSaved();
_.agHelper.GetNClick(_.dataSources._queryDoc);
_.agHelper.AssertElementVisible(_.dataSources._globalSearchModal);
_.agHelper.AssertElementVisible(
_.dataSources._globalSearchInput("MySQL"),
);
_.agHelper.AssertNewTabOpened(() => {
_.agHelper.GetNClick(_.dataSources._queryDoc);
});
});
});

View File

@ -12,8 +12,9 @@ describe("Google Sheets datasource test cases", function () {
dataSources.NavigateToDSCreateNew();
dataSources.CreatePlugIn("Google Sheets");
VerifyFunctionDropdown([
"Read/Write | Selected Google Sheets",
"Read/Write | All Google Sheets",
"Read / Write / Delete | Selected Google Sheets",
"Read / Write / Delete | All Google Sheets",
"Read / Write | All Google Sheets",
"Read | All Google Sheets",
]);
dataSources.SaveDSFromDialog(false);

View File

@ -2,7 +2,9 @@
"introModal": ".t--onboarding-introduction-modal",
"introModalBuild": ".t--introduction-modal-build-button",
"introModalWelcomeTourBtn": ".t--introduction-modal-welcome-tour-button",
"introModalCloseBtn": ".t--how-appsmith-works-modal-close",
"statusbar": ".t--onboarding-statusbar",
"statusbarClose": "[data-cy='statusbar-skip']",
"checklistStatus": ".t--checklist-complete-status",
"checklistDatasourceBtn": ".t--checklist-datasource-button",
"checklistBack": ".t--checklist-back",

View File

@ -34,7 +34,7 @@
"apiInputTab": "li:contains('API Input')",
"paginationOption": ".t--apiFormPaginationType div>input",
"paginationWithTable": "//label[contains(text(),'Paginate with Table Page No')] ",
"paginationWithUrl": "//label[contains(text(),'Paginate with Response Url')]",
"paginationWithUrl": "//label[contains(text(),'Paginate with Response URL')]",
"panigationNextUrl": ".t--apiFormPaginationNext div>textarea",
"panigationPrevUrl": ".t--apiFormPaginationPrev div>textarea",
"TestNextUrl": ".t--apiFormPaginationNextTest",
@ -63,4 +63,4 @@
"multipartTypeDropdown": "button:contains('Type')",
"confirmBeforeExecute": "[name=confirmBeforeExecute]",
"runQueryButton": ".t--apiFormRunBtn"
}
}

View File

@ -30,6 +30,7 @@
"cypress-file-upload": "^4.1.1",
"cypress-image-snapshot": "^4.0.1",
"cypress-multi-reporters": "^1.2.4",
"cypress-plugin-tab": "^1.0.5",
"cypress-real-events": "^1.7.1",
"cypress-wait-until": "^1.7.2",
"cypress-xpath": "^1.4.0",

View File

@ -22,3 +22,4 @@ export const debuggerHelper = ObjectsRegistry.DebuggerHelper;
export const templates = ObjectsRegistry.Templates;
export const peekOverlay = ObjectsRegistry.PeekOverlay;
export const installer = ObjectsRegistry.LibraryInstaller;
export const onboarding = ObjectsRegistry.Onboarding;

View File

@ -21,6 +21,7 @@ import { PageSettings } from "../Pages/AppSettings/PageSettings";
import { ThemeSettings } from "../Pages/AppSettings/ThemeSettings";
import { EmbedSettings } from "../Pages/AppSettings/EmbedSettings";
import { Templates } from "../Pages/Templates";
import { Onboarding } from "../Pages/Onboarding";
export class ObjectsRegistry {
private static aggregateHelper__: AggregateHelper;
@ -206,6 +207,14 @@ export class ObjectsRegistry {
}
return ObjectsRegistry.templates__;
}
private static onboarding__: Onboarding;
static get Onboarding(): Onboarding {
if (ObjectsRegistry.onboarding__ === undefined) {
ObjectsRegistry.onboarding__ = new Onboarding();
}
return ObjectsRegistry.onboarding__;
}
}
export const initLocalstorageRegistry = () => {

View File

@ -1169,6 +1169,18 @@ export class AggregateHelper {
}
}
public AssertNewTabOpened(openTabFunc: () => void) {
cy.window().then((win) => {
cy.spy(win, "open").as("windowOpen");
openTabFunc();
cy.get("@windowOpen").should(
"be.calledWith",
Cypress.sinon.match.string,
"_blank",
);
});
}
//Not used:
// private xPathToCss(xpath: string) {
// return xpath

View File

@ -4,6 +4,8 @@ import HomePageLocators from "../../locators/HomePage";
export class HomePage {
private agHelper = ObjectsRegistry.AggregateHelper;
private locator = ObjectsRegistry.CommonLocators;
private entityExplorer = ObjectsRegistry.EntityExplorer;
private onboarding = ObjectsRegistry.Onboarding;
private _username = "input[name='username']";
private _password = "input[name='password']";
@ -208,10 +210,16 @@ export class HomePage {
this.agHelper.AssertElementVisible(this._homeAppsmithImage);
}
public CreateNewApplication() {
public CreateNewApplication(skipSignposting = true) {
cy.get(this._homePageAppCreateBtn).first().click({ force: true });
this.agHelper.ValidateNetworkStatus("@createNewApplication", 201);
cy.get(this.locator._loading).should("not.exist");
if (skipSignposting) {
this.agHelper.AssertElementVisible(this.entityExplorer._entityExplorer);
this.onboarding.closeIntroModal();
this.onboarding.skipSignposting();
}
}
//Maps to CreateAppForWorkspace in command.js

View File

@ -0,0 +1,83 @@
import { ObjectsRegistry } from "../Objects/Registry";
const OnboardingLocator = require("../../locators/FirstTimeUserOnboarding.json");
export class Onboarding {
private _aggregateHelper = ObjectsRegistry.AggregateHelper;
completeSignposting() {
cy.get(OnboardingLocator.introModalBuild).click();
cy.get(OnboardingLocator.statusbar).click();
cy.get(OnboardingLocator.checklistStatus).should("be.visible");
cy.get(OnboardingLocator.checklistStatus).should("contain", "0 of 5");
cy.get(OnboardingLocator.checklistBack).click();
cy.get(OnboardingLocator.statusbar).click();
cy.get(OnboardingLocator.checklistDatasourceBtn).should("not.be.disabled");
cy.get(OnboardingLocator.checklistDatasourceBtn).click();
cy.get(OnboardingLocator.datasourcePage).should("be.visible");
cy.get(OnboardingLocator.datasourceMock).first().click();
cy.wait(1000);
cy.get(OnboardingLocator.statusbar).click();
cy.get(OnboardingLocator.checklistStatus).should("contain", "1 of 5");
cy.get(OnboardingLocator.checklistDatasourceBtn).should("not.exist");
cy.get(OnboardingLocator.checklistActionBtn).should("be.visible");
cy.get(OnboardingLocator.checklistActionBtn).click();
cy.get(OnboardingLocator.createQuery).should("be.visible");
cy.get(OnboardingLocator.createQuery).click();
cy.wait(1000);
cy.get(OnboardingLocator.statusbar).click();
cy.get(OnboardingLocator.checklistStatus).should("contain", "2 of 5");
cy.get(OnboardingLocator.checklistActionBtn).should("not.exist");
cy.get(OnboardingLocator.checklistWidgetBtn).should("be.visible");
cy.get(OnboardingLocator.checklistWidgetBtn).click();
cy.get(OnboardingLocator.widgetSidebar).should("be.visible");
(cy as any).dragAndDropToCanvas("textwidget", { x: 400, y: 400 });
cy.get(OnboardingLocator.statusbar).click();
cy.get(OnboardingLocator.checklistStatus).should("contain", "3 of 5");
cy.get(OnboardingLocator.checklistWidgetBtn).should("not.exist");
cy.get(OnboardingLocator.checklistConnectionBtn).should("be.visible");
cy.get(OnboardingLocator.checklistConnectionBtn).click();
cy.get(OnboardingLocator.snipingBanner).should("be.visible");
cy.get(OnboardingLocator.snipingTextWidget)
.first()
.trigger("mouseover", { force: true })
.wait(500);
cy.get(OnboardingLocator.widgetName).should("be.visible");
cy.get(OnboardingLocator.widgetName).click();
cy.get(OnboardingLocator.statusbar).click();
cy.get(OnboardingLocator.checklistStatus).should("contain", "4 of 5");
cy.get(OnboardingLocator.checklistConnectionBtn).should("not.exist");
let open: any;
cy.window().then((window: any) => {
open = window.open;
window.open = Cypress._.noop;
});
cy.get(OnboardingLocator.checklistDeployBtn).should("be.visible");
cy.get(OnboardingLocator.checklistDeployBtn).click();
cy.get(OnboardingLocator.checklistStatus).should("contain", "5 of 5");
cy.get(OnboardingLocator.checklistDeployBtn).should("not.exist");
cy.window().then((window) => {
window.open = open;
});
}
closeIntroModal() {
cy.get("body").then(($body) => {
if ($body.find(OnboardingLocator.introModalCloseBtn).length) {
this._aggregateHelper.GetNClick(OnboardingLocator.introModalCloseBtn);
}
});
}
skipSignposting() {
cy.get("body").then(($body) => {
if ($body.find(OnboardingLocator.statusbarClose).length) {
this._aggregateHelper.GetNClick(OnboardingLocator.statusbarClose);
}
});
}
}

View File

@ -316,8 +316,10 @@ export class PropertyPane {
toVerifySave && this.agHelper.AssertAutoSave();
}
public TypeTextIntoField(endp: string, value: string) {
this.RemoveText(endp);
public TypeTextIntoField(endp: string, value: string, removeText = true) {
if (removeText) {
this.RemoveText(endp);
}
cy.get(
this.locator._propertyControl +
endp.replace(/ +/g, "").toLowerCase() +

View File

@ -32,14 +32,15 @@ export class Table {
public locator = ObjectsRegistry.CommonLocators;
public propPane = ObjectsRegistry.PropertyPane;
private _tableWrap = "//div[@class='tableWrap']";
private _tableWrap = "//div[contains(@class,'tableWrap')]";
private _tableHeader =
this._tableWrap + "//div[@class='thead']//div[@class='tr'][1]";
this._tableWrap +
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]";
private _columnHeader = (columnName: string) =>
this._tableWrap +
"//div[@class='thead']//div[@class='tr'][1]//div[@role='columnheader']//span[text()='" +
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]//div[@role='columnheader']//div[contains(text(),'" +
columnName +
"']/parent::div/parent::div/parent::div";
"')]/parent::div/parent::div";
private _tableWidgetVersion = (version: "v1" | "v2") =>
`.t--widget-tablewidget${version == "v1" ? "" : version}`;
private _nextPage = (version: "v1" | "v2") =>

View File

@ -286,9 +286,13 @@ Cypress.Commands.add("CreateAppInFirstListedWorkspace", (appname) => {
//cy.reload();
cy.get("#loading").should("not.exist");
cy.get("#sidebar").should("be.visible");
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000);
// If the into modal is open close it
cy.skipSignposting();
cy.AppSetupForRename();
cy.get(homePage.applicationName).type(appname + "{enter}");
cy.wait("@updateApplication").should(

View File

@ -23,6 +23,7 @@ import { CURRENT_REPO, REPO } from "../fixtures/REPO";
const apiwidget = require("../locators/apiWidgetslocator.json");
const explorer = require("../locators/explorerlocators.json");
const onboardingLocators = require("../locators/FirstTimeUserOnboarding.json");
const datasource = require("../locators/DatasourcesEditor.json");
const viewWidgetsPage = require("../locators/ViewWidgets.json");
const generatePage = require("../locators/GeneratePage.json");
@ -35,6 +36,7 @@ import { ObjectsRegistry } from "../support/Objects/Registry";
const propPane = ObjectsRegistry.PropertyPane;
const agHelper = ObjectsRegistry.AggregateHelper;
const locators = ObjectsRegistry.CommonLocators;
const onboarding = ObjectsRegistry.Onboarding;
let pageidcopy = " ";
const chainStart = Symbol();
@ -272,11 +274,14 @@ Cypress.Commands.add("Signup", (uname, pword) => {
Cypress.Commands.add("LoginFromAPI", (uname, pword) => {
cy.location().then((loc) => {
let baseURL = Cypress.config().baseUrl;
baseURL = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
cy.visit({
method: "POST",
url: "api/v1/login",
headers: {
origin: loc.origin,
origin: baseURL,
},
followRedirect: true,
body: {
@ -287,9 +292,15 @@ Cypress.Commands.add("LoginFromAPI", (uname, pword) => {
.then(() => cy.location())
.then((loc) => {
expect(loc.href).to.equal(loc.origin + "/applications");
cy.wait("@getMe");
cy.wait("@applications").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
cy.wait("@getReleaseItems");
});
});
cy.wait(2000); //for the page elements to load!
});
Cypress.Commands.add("DeleteApp", (appName) => {
@ -597,18 +608,16 @@ Cypress.Commands.add("generateUUID", () => {
Cypress.Commands.add("addDsl", (dsl) => {
let currentURL, pageid, layoutId, appId;
appId = localStorage.getItem("applicationId");
cy.url().then((url) => {
currentURL = url;
pageid = currentURL.split("/")[5]?.split("-").pop();
cy.log(pageidcopy + "page id copy");
cy.log(pageid + "page id");
appId = localStorage.getItem("applicationId");
//Fetch the layout id
cy.request("GET", "api/v1/pages/" + pageid).then((response) => {
const respBody = JSON.stringify(response.body);
layoutId = JSON.parse(respBody).data.layouts[0].id;
cy.log("appid:" + appId);
const data = JSON.parse(respBody).data;
layoutId = data.layouts[0].id;
appId = data.applicationId;
// Dumping the DSL to the created page
cy.request({
method: "PUT",
@ -627,6 +636,7 @@ Cypress.Commands.add("addDsl", (dsl) => {
cy.log(response.body);
expect(response.status).equal(200);
cy.reload();
cy.wait("@getWorkspace");
});
});
});
@ -924,6 +934,7 @@ Cypress.Commands.add("startServerAndRoutes", () => {
cy.route("GET", "/api/v1/datasources?workspaceId=*").as("getDataSources");
cy.route("GET", "/api/v1/pages?*mode=EDIT").as("getPagesForCreateApp");
cy.route("GET", "/api/v1/pages?*mode=PUBLISHED").as("getPagesForViewApp");
cy.route("GET", "/api/v1/applications/releaseItems").as("getReleaseItems");
cy.route("POST");
cy.route("GET", "/api/v1/pages/*").as("getPage");
@ -2098,3 +2109,8 @@ Cypress.Commands.add("SelectFromMultiSelect", (options) => {
});
cy.document().its("body").type("{esc}");
});
Cypress.Commands.add("skipSignposting", () => {
onboarding.closeIntroModal();
onboarding.skipSignposting();
});

View File

@ -30,8 +30,20 @@ import "./queryCommands";
import "./widgetCommands";
import "./themeCommands";
import "./AdminSettingsCommands";
import "cypress-plugin-tab";
/// <reference types="cypress-xpath" />
let rapidMode = {
enabled: false, // Set to true to disable app creation
appName: "cf023e29", // Replace it with your app name
pageName: "page1", // Replace it with the page name
pageID: "644d0ec870cec01248edfc9a", // Replace it with pageID
url: function () {
return `app/${this.appName}/${this.pageName}-${this.pageID}/edit`;
},
};
Cypress.on("uncaught:exception", () => {
// returning false here prevents Cypress from
// failing the test
@ -45,6 +57,24 @@ Cypress.on("fail", (error) => {
Cypress.env("MESSAGES", MESSAGES);
before(function () {
if (rapidMode.enabled) {
cy.startServerAndRoutes();
cy.getCookie("SESSION").then((cookie) => {
if (!cookie) {
cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD"));
}
});
Cypress.Cookies.preserveOnce("SESSION", "remember_token");
cy.visit(rapidMode.url());
cy.wait("@getWorkspace");
}
});
before(function () {
if (rapidMode.enabled) {
return;
}
//console.warn = () => {}; //to remove all warnings in cypress console
initLocalstorage();
initLocalstorageRegistry();
@ -85,12 +115,14 @@ before(function () {
});
before(function () {
if (rapidMode.enabled) {
return;
}
//console.warn = () => {};
Cypress.Cookies.preserveOnce("SESSION", "remember_token");
const username = Cypress.env("USERNAME");
const password = Cypress.env("PASSWORD");
cy.LoginFromAPI(username, password);
cy.wait("@getMe");
cy.wait(3000);
cy.get(".t--applications-container .createnew")
.should("be.visible")
@ -121,6 +153,9 @@ beforeEach(function () {
});
after(function () {
if (rapidMode.enabled) {
return;
}
//-- Deleting the application by Api---//
cy.DeleteAppByApi();
//-- LogOut Application---//

View File

@ -22,8 +22,6 @@ server {
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_SMART_LOOK_ID__ '${APPSMITH_SMART_LOOK_ID}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_ENABLED__ '${APPSMITH_MARKETPLACE_ENABLED}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';

View File

@ -32,8 +32,6 @@ server {
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_SMART_LOOK_ID__ '${APPSMITH_SMART_LOOK_ID}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_ENABLED__ '${APPSMITH_MARKETPLACE_ENABLED}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';

View File

@ -29,8 +29,6 @@ server {
proxy_pass __APPSMITH_CLIENT_PROXY_PASS__;
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_SMART_LOOK_ID__ '${APPSMITH_SMART_LOOK_ID}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_ENABLED__ '${APPSMITH_MARKETPLACE_ENABLED}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';

View File

@ -55,8 +55,6 @@ module.exports = {
smartLook: {
id: parseConfig("__APPSMITH_SMART_LOOK_ID__"),
},
enableGoogleOAuth: parseConfig("__APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__"),
enableGithubOAuth: parseConfig("__APPSMITH_OAUTH2_GITHUB_CLIENT_ID__"),
disableLoginForm: parseConfig("__APPSMITH_FORM_LOGIN_DISABLED__"),
disableSignup: parseConfig("__APPSMITH_SIGNUP_DISABLED__"),
enableRapidAPI: parseConfig("__APPSMITH_MARKETPLACE_ENABLED__"),

View File

@ -74,7 +74,6 @@
"codemirror-graphql": "^1.2.14",
"copy-to-clipboard": "^3.3.1",
"core-js": "^3.9.1",
"country-flag-emoji-polyfill": "^0.1.4",
"craco-alias": "^2.1.1",
"craco-babel-loader": "^1.0.4",
"cypress-log-to-output": "^1.1.2",
@ -268,6 +267,7 @@
"cypress-file-upload": "^4.1.1",
"cypress-image-snapshot": "^4.0.1",
"cypress-multi-reporters": "^1.2.4",
"cypress-plugin-tab": "^1.0.5",
"cypress-real-events": "^1.7.1",
"cypress-wait-until": "^1.7.2",
"cypress-xpath": "^1.4.0",

View File

@ -16,11 +16,13 @@
"@react-aria/utils": "^3.16.0",
"@react-aria/visually-hidden": "^3.8.0",
"@react-spectrum/utils": "^3.9.0",
"@react-stately/checkbox": "^3.4.1",
"@react-stately/toggle": "^3.5.1",
"@react-types/button": "^3.7.1",
"@react-types/checkbox": "^3.4.3",
"@react-types/shared": "^3.17.0",
"classnames": "*"
"@react-types/label": "^3.7.3",
"classnames": "*",
"@react-types/shared": "^3.17.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"

View File

@ -1,11 +1,10 @@
import type { RefObject } from "react";
import React, { forwardRef } from "react";
import { useFocusableRef } from "@react-spectrum/utils";
import classNames from "classnames";
import { FocusRing } from "@react-aria/focus";
import { mergeProps } from "@react-aria/utils";
import { useButton } from "@react-aria/button";
import { useFocusRing } from "@react-aria/focus";
import { useHover } from "@react-aria/interactions";
import type { RefObject } from "react";
import { useFocusableRef } from "@react-spectrum/utils";
import type { FocusableRef } from "@react-types/shared";
import type { ButtonProps as SpectrumButtonProps } from "@react-types/button";
@ -23,20 +22,19 @@ export const Button = forwardRef((props: ButtonProps, ref: ButtonRef) => {
const domRef = useFocusableRef(ref) as RefObject<HTMLButtonElement>;
const { buttonProps, isPressed } = useButton(props, domRef);
const { hoverProps, isHovered } = useHover({ isDisabled });
const { focusProps, isFocusVisible } = useFocusRing({ autoFocus });
return (
<FocusRing autoFocus={autoFocus} focusRingClass="focus-ring">
<button
{...mergeProps(buttonProps, hoverProps)}
className={classNames(className, {
"is-disabled": isDisabled,
"is-active": isPressed || isActive,
"is-hovered": isHovered || isHover,
})}
ref={domRef}
>
{children}
</button>
</FocusRing>
<button
{...mergeProps(buttonProps, hoverProps, focusProps)}
className={className}
data-active={isPressed || isActive ? "" : undefined}
data-disabled={isDisabled ? "" : undefined}
data-focused={isFocusVisible ? "" : undefined}
data-hovered={isHovered || isHover ? "" : undefined}
ref={domRef}
>
{children}
</button>
);
});

View File

@ -1,20 +1,23 @@
import classNames from "classnames";
import { mergeProps } from "@react-aria/utils";
import { useFocusRing } from "@react-aria/focus";
import React, { forwardRef, useRef } from "react";
import { useCheckbox } from "@react-aria/checkbox";
import { useHover } from "@react-aria/interactions";
import CheckIcon from "remixicon-react/CheckLineIcon";
import { useToggleState } from "@react-stately/toggle";
import { useFocusableRef } from "@react-spectrum/utils";
import type { FocusableRef } from "@react-types/shared";
import SubtractIcon from "remixicon-react/SubtractLineIcon";
import React, { forwardRef, useContext, useRef } from "react";
import { useVisuallyHidden } from "@react-aria/visually-hidden";
import type { FocusableRef, StyleProps } from "@react-types/shared";
import type { SpectrumCheckboxProps } from "@react-types/checkbox";
import { useCheckbox, useCheckboxGroupItem } from "@react-aria/checkbox";
export interface CheckboxProps extends SpectrumCheckboxProps {
import { CheckboxGroupContext } from "./context";
export interface CheckboxProps
extends Omit<SpectrumCheckboxProps, keyof StyleProps> {
icon?: React.ReactNode;
className?: string;
labelPosition?: "left" | "right";
}
export type CheckboxRef = FocusableRef<HTMLLabelElement>;
@ -34,25 +37,55 @@ export const Checkbox = forwardRef((props: CheckboxProps, ref: CheckboxRef) => {
const domRef = useFocusableRef(ref, inputRef);
const { visuallyHiddenProps } = useVisuallyHidden();
const { hoverProps, isHovered } = useHover({ isDisabled });
const { inputProps } = useCheckbox(props, state, inputRef);
const { focusProps, isFocusVisible } = useFocusRing({ autoFocus });
const computedClassnames = classNames(className, {
"is-disabled": isDisabled,
"is-hovered": isHovered,
"is-checked": state.isSelected,
"is-indeterminate": isIndeterminate,
"is-invalid": validationState === "invalid",
"is-focused": isFocusVisible,
});
// The hooks will be swapped based on whether the checkbox is a part of a CheckboxGroup.
// Although this approach is not conventional since hooks cannot usually be called conditionally,
// it should be safe in this case since the checkbox is not expected to be added or removed from the group.
const groupState = useContext(CheckboxGroupContext);
const { inputProps } = groupState
? // eslint-disable-next-line react-hooks/rules-of-hooks
useCheckboxGroupItem(
{
...props,
// Value is optional for standalone checkboxes, but required for CheckboxGroup items;
// it's passed explicitly here to avoid typescript error (requires ignore).
// @ts-expect-error value is required in checkbox group items
value: props.value,
// Only pass isRequired and validationState to react-aria if they came from
// the props for this individual checkbox, and not from the group via context.
isRequired: props.isRequired,
validationState: props.validationState,
},
groupState,
inputRef,
)
: // eslint-disable-next-line react-hooks/rules-of-hooks
useCheckbox(props, state, inputRef);
const dataState = isIndeterminate
? "indeterminate"
: inputProps.checked
? "checked"
: "unchecked";
return (
<label {...hoverProps} className={computedClassnames} ref={domRef}>
<label
{...hoverProps}
className={className}
data-disabled={isDisabled ? "" : undefined}
data-focussed={isFocusVisible ? "" : undefined}
data-hovered={isHovered ? "" : undefined}
data-invalid={validationState === "invalid" ? "" : undefined}
data-label=""
data-state={dataState}
ref={domRef}
>
<input
{...mergeProps(inputProps, visuallyHiddenProps, focusProps)}
ref={inputRef}
/>
<span aria-hidden="true" className="icon" role="presentation">
<span aria-hidden="true" data-icon="" role="presentation">
{isIndeterminate ? <SubtractIcon /> : icon}
</span>
{children}

View File

@ -0,0 +1,44 @@
import React, { forwardRef } from "react";
import type { DOMRef } from "@react-types/shared";
import { useDOMRef } from "@react-spectrum/utils";
import { useCheckboxGroup } from "@react-aria/checkbox";
import type { StyleProps } from "@react-types/shared";
import { useCheckboxGroupState } from "@react-stately/checkbox";
import type { SpectrumCheckboxGroupProps } from "@react-types/checkbox";
import { Field } from "../Field";
import { CheckboxGroupContext } from "./context";
export type CheckboxGroupRef = DOMRef<HTMLDivElement>;
export interface CheckboxGroupProps
extends Omit<SpectrumCheckboxGroupProps, keyof StyleProps> {
className?: string;
}
export const CheckboxGroup = forwardRef(
(props: CheckboxGroupProps, ref: CheckboxGroupRef) => {
const { children, className, orientation = "vertical" } = props;
const domRef = useDOMRef(ref);
const state = useCheckboxGroupState(props);
const { descriptionProps, errorMessageProps, groupProps, labelProps } =
useCheckboxGroup(props, state);
return (
<Field
{...props}
descriptionProps={descriptionProps}
errorMessageProps={errorMessageProps}
includeNecessityIndicatorInAccessibilityName
labelProps={labelProps}
ref={domRef}
wrapperClassName={className}
>
<div {...groupProps} data-field-group data-orientation={orientation}>
<CheckboxGroupContext.Provider value={state}>
{children}
</CheckboxGroupContext.Provider>
</div>
</Field>
);
},
);

View File

@ -0,0 +1,6 @@
import React from "react";
import type { CheckboxGroupState } from "@react-stately/checkbox";
export const CheckboxGroupContext =
React.createContext<CheckboxGroupState | null>(null);

View File

@ -1,2 +1,4 @@
export { Checkbox } from "./Checkbox";
export { CheckboxGroup } from "./CheckboxGroup";
export type { CheckboxProps, CheckboxRef } from "./Checkbox";
export type { CheckboxGroupProps, CheckboxGroupRef } from "./CheckboxGroup";

View File

@ -0,0 +1,25 @@
import React, { forwardRef } from "react";
import type { HTMLAttributes } from "react";
import { useDOMRef } from "@react-spectrum/utils";
import AlertIcon from "remixicon-react/AlertFillIcon";
import type { DOMRef, SpectrumHelpTextProps } from "@react-types/shared";
interface HelpTextProps extends SpectrumHelpTextProps {
errorMessageProps?: HTMLAttributes<HTMLElement>;
}
export const ErrorText = forwardRef(
(props: HelpTextProps, ref: DOMRef<HTMLDivElement>) => {
const { errorMessage, errorMessageProps, showErrorIcon } = props;
const domRef = useDOMRef(ref);
return (
<div data-field-error-text="">
{showErrorIcon && <AlertIcon />}
<span {...errorMessageProps} ref={domRef}>
{errorMessage}
</span>
</div>
);
},
);

View File

@ -0,0 +1,95 @@
import React, { forwardRef } from "react";
import { filterDOMProps } from "@react-aria/utils";
import type { SpectrumFieldProps } from "@react-types/label";
import { Label } from "./Label";
import { ErrorText } from "./ErrorText";
export type FieldProps = SpectrumFieldProps;
export type FieldRef = any;
export const Field = forwardRef((props: FieldProps, ref: FieldRef) => {
const {
label,
labelPosition = "top",
labelAlign,
isRequired,
necessityIndicator,
includeNecessityIndicatorInAccessibilityName,
validationState,
errorMessage,
isDisabled,
showErrorIcon,
labelProps,
errorMessageProps = {},
elementType,
children,
wrapperClassName,
wrapperProps = {},
...otherProps
} = props;
const hasErrorText = errorMessage && validationState === "invalid";
const renderErrorText = () => {
return (
<ErrorText
errorMessage={errorMessage}
errorMessageProps={errorMessageProps}
isDisabled={isDisabled}
showErrorIcon={showErrorIcon}
validationState={validationState}
/>
);
};
const renderChildren = () => {
if (labelPosition === "side") {
return (
<div className="wrapper">
{children}
{hasErrorText && renderErrorText()}
</div>
);
}
return (
<>
{children}
{hasErrorText && renderErrorText()}
</>
);
};
const labelAndContextualHelp = label && (
<Label
{...labelProps}
elementType={elementType}
includeNecessityIndicatorInAccessibilityName={
includeNecessityIndicatorInAccessibilityName
}
isRequired={isRequired}
labelAlign={labelAlign}
labelPosition={labelPosition}
necessityIndicator={necessityIndicator}
>
{label}
</Label>
);
return (
<div
{...filterDOMProps(otherProps)}
{...wrapperProps}
className={wrapperClassName}
data-align={labelAlign}
data-disabled={isDisabled}
data-field=""
data-position={labelPosition}
ref={ref}
>
<div>{labelAndContextualHelp}</div>
{renderChildren()}
</div>
);
});

View File

@ -0,0 +1,71 @@
import React, { forwardRef } from "react";
import { useDOMRef } from "@react-spectrum/utils";
import type { DOMRef } from "@react-types/shared";
import { filterDOMProps } from "@react-aria/utils";
import AsteriskIcon from "remixicon-react/AsteriskIcon";
import type { SpectrumLabelProps } from "@react-types/label";
export interface LabelProps extends SpectrumLabelProps {
isEmphasized?: boolean;
}
export const Label = forwardRef(
(props: SpectrumLabelProps, ref: DOMRef<HTMLLabelElement>) => {
const {
children,
labelPosition = "top",
labelAlign = labelPosition === "side" ? "start" : null,
isRequired,
necessityIndicator = isRequired != null ? "icon" : null,
includeNecessityIndicatorInAccessibilityName = false,
htmlFor,
for: labelFor,
elementType: ElementType = "label",
onClick,
...otherProps
} = props;
const domRef = useDOMRef(ref);
const necessityLabel = isRequired ? "(required)" : "(optional)";
const icon = (
<AsteriskIcon
aria-label={
includeNecessityIndicatorInAccessibilityName
? "(required)"
: undefined
}
data-field-necessity-indicator-icon=""
/>
);
return (
<ElementType
data-align={labelAlign}
data-field-label=""
data-position={labelPosition}
{...filterDOMProps(otherProps)}
htmlFor={ElementType === "label" ? labelFor || htmlFor : undefined}
onClick={onClick}
ref={domRef}
>
{children}
{/* necessityLabel is hidden to screen readers if the field is required because
* aria-required is set on the field in that case. That will already be announced,
* so no need to duplicate it here. If optional, we do want it to be announced here. */}
{necessityIndicator === "label" && (
<span
aria-hidden={
!includeNecessityIndicatorInAccessibilityName
? isRequired
: undefined
}
>
{necessityLabel}
</span>
)}
{necessityIndicator === "icon" && isRequired && icon}
</ElementType>
);
},
);

View File

@ -0,0 +1,3 @@
export * from "./Field";
export type { FieldProps, FieldRef } from "./Field";
export type { LabelProps } from "./Label";

View File

@ -1,2 +1,4 @@
// components
export * from "./components/Button";
export * from "./components/Checkbox";
export * from "./components/Field";

View File

@ -9,14 +9,6 @@
"prettier:ci": "prettier --check .",
"build:tokens": "npx ts-node ./src/utils/buildTokens.ts"
},
"dependencies": {
"react": "*",
"react-dom": "*"
},
"devDependencies": {
"@types/react": "*",
"@types/react-dom": "*"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
}

View File

@ -1,27 +1,31 @@
{
"color": {
"bg": {
"value": "#f9fafe",
"type": "color"
},
"bg-accent": {
"value": "#553de9",
"type": "color"
},
"bg-accent-hover": {
"value": "#6e61ff",
"value": "#5c48f4",
"type": "color"
},
"bg-accent-active": {
"value": "#8f85ff",
"value": "#5033e1",
"type": "color"
},
"bg-accent-subtle-hover": {
"value": "#b6adff",
"value": "#e7ddff",
"type": "color"
},
"bg-accent-subtle-active": {
"value": "#d7d0ff",
"value": "#bbaee2",
"type": "color"
},
"bd-accent": {
"value": "#553de9",
"fg": {
"value": "#040411",
"type": "color"
},
"fg-accent": {
@ -29,11 +33,35 @@
"type": "color"
},
"fg-on-accent": {
"value": "#fff",
"value": "#f8f9ff",
"type": "color"
},
"fg-negative": {
"value": "#d91921",
"type": "color"
},
"bd-accent": {
"value": "#553de9",
"type": "color"
},
"bd-neutral": {
"value": "#63646e",
"type": "color"
},
"bd-neutral-hover": {
"value": "#6c6d77",
"type": "color"
},
"bd-focus": {
"value": "#2a82ea",
"value": "#7b6200",
"type": "color"
},
"bd-negative": {
"value": "#d91921",
"type": "color"
},
"bd-negative-hover": {
"value": "#b90707",
"type": "color"
}
},

View File

@ -1,20 +1,15 @@
import type Color from "colorjs.io";
import Color from "colorjs.io";
import type { ColorTypes } from "colorjs.io/types/src/color";
import { parse } from "../";
export class ColorsAccessor {
private color: Color;
color: Color;
constructor(color: ColorTypes) {
this.color = parse(color);
this.color = new Color(color);
return this;
}
get hex() {
return this.color.toString({ format: "hex" });
}
/* Lightness */
get isVeryDark() {
return this.color.oklch.l < 0.3;

View File

@ -1,11 +1,11 @@
import { contrast, lighten, setLch } from "../colorUtils";
import { ColorsAccessor } from "../ColorsAccessor";
import type Color from "colorjs.io";
import type { ColorTypes } from "colorjs.io/types/src/color";
import type { ColorModeTheme } from "./types";
export class DarkModeTheme implements ColorModeTheme {
private readonly seedColor: string;
private readonly seedColor: Color;
private readonly seedLightness: number;
private readonly seedChroma: number;
private readonly seedHue: number;
@ -13,9 +13,15 @@ export class DarkModeTheme implements ColorModeTheme {
private readonly seedIsAchromatic: boolean;
constructor(private color: ColorTypes) {
const { chroma, hex, hue, isAchromatic, isVeryDark, lightness } =
new ColorsAccessor(color);
this.seedColor = hex;
const {
chroma,
color: seedColor,
hue,
isAchromatic,
isVeryDark,
lightness,
} = new ColorsAccessor(color);
this.seedColor = seedColor;
this.seedLightness = lightness;
this.seedChroma = chroma;
this.seedHue = hue;
@ -25,19 +31,22 @@ export class DarkModeTheme implements ColorModeTheme {
public getColors = () => {
return {
bg: this.bg,
bgAccent: this.bgAccent,
bgAccentHover: this.bgAccentHover,
bgAccentActive: this.bgAccentActive,
bgAccentSubtleHover: this.bgAccentSubtleHover,
bgAccentSubtleActive: this.bgAccentSubtleActive,
fg: this.fg,
fgAccent: this.fgAccent,
fgOnAccent: this.fgOnAccent,
bdAccent: this.bdAccent,
bdFocus: this.bdFocus,
bdNeutral: this.bdNeutral,
bdNeutralHover: this.bdNeutralHover,
bg: this.bg.toString({ format: "hex" }),
bgAccent: this.bgAccent.toString({ format: "hex" }),
bgAccentHover: this.bgAccentHover.toString({ format: "hex" }),
bgAccentActive: this.bgAccentActive.toString({ format: "hex" }),
bgAccentSubtleHover: this.bgAccentSubtleHover.toString({ format: "hex" }),
bgAccentSubtleActive: this.bgAccentSubtleActive.toString({
format: "hex",
}),
fg: this.fg.toString({ format: "hex" }),
fgAccent: this.fgAccent.toString({ format: "hex" }),
fgOnAccent: this.fgOnAccent.toString({ format: "hex" }),
fgNegative: this.fgNegative,
bdAccent: this.bdAccent.toString({ format: "hex" }),
bdFocus: this.bdFocus.toString({ format: "hex" }),
bdNeutral: this.bdNeutral.toString({ format: "hex" }),
bdNeutralHover: this.bdNeutralHover.toString({ format: "hex" }),
bdNegative: this.bdNegative,
bdNegativeHover: this.bdNegativeHover,
};
@ -47,179 +56,177 @@ export class DarkModeTheme implements ColorModeTheme {
* Background colors
*/
private get bg() {
const color = this.seedColor.clone();
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.15,
c: 0,
});
color.oklch.l = 0.15;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.15,
c: 0.064,
});
color.oklch.l = 0.15;
color.oklch.c = 0.064;
return color;
}
private get bgAccent() {
const color = this.seedColor.clone();
if (this.seedIsVeryDark) {
return setLch(this.seedColor, {
l: 0.3,
});
color.oklch.l = 0.3;
return color;
}
return this.seedColor;
return color;
}
private get bgAccentHover() {
return lighten(this.bgAccent, 1.06);
return this.bgAccent.clone().lighten(0.06);
}
private get bgAccentActive() {
return lighten(this.bgAccentHover, 0.9);
return this.bgAccentHover.clone().darken(0.1);
}
// used only for generating child colors, not used as a token
private get bgAccentSubtle() {
let currentColor = this.seedColor;
const color = this.seedColor.clone();
if (this.seedLightness > 0.3) {
currentColor = setLch(currentColor, {
l: 0.3,
});
color.oklch.l = 0.3;
}
if (this.seedChroma > 0.112 && !this.seedIsAchromatic) {
currentColor = setLch(currentColor, {
c: 0.112,
});
color.oklch.c = 0.112;
}
return currentColor;
return color;
}
private get bgAccentSubtleHover() {
return lighten(this.bgAccentSubtle, 1.06);
return this.bgAccentSubtle.clone().lighten(0.06);
}
private get bgAccentSubtleActive() {
return lighten(this.bgAccentSubtle, 0.9);
return this.bgAccentSubtleHover.clone().darken(0.1);
}
/*
* Foreground colors
*/
private get fg() {
const color = this.seedColor.clone();
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.965,
c: 0,
});
color.oklch.l = 0.965;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.965,
c: 0.024,
});
color.oklch.l = 0.965;
color.oklch.c = 0.024;
return color;
}
private get fgAccent() {
if (contrast(this.seedColor, this.bg) <= 60) {
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) <= 60) {
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.79,
c: 0,
});
color.oklch.l = 0.79;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.79,
c: 0.136,
});
color.oklch.l = 0.79;
color.oklch.c = 0.136;
return color;
}
return this.seedColor;
return color;
}
private get fgOnAccent() {
if (contrast(this.seedColor, this.bg) <= 40) {
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) <= 40) {
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.985,
c: 0,
});
color.oklch.l = 0.985;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.985,
c: 0.016,
});
color.oklch.l = 0.985;
color.oklch.c = 0.016;
return color;
}
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.15,
c: 0,
});
color.oklch.l = 0.15;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.15,
c: 0.064,
});
color.oklch.l = 0.15;
color.oklch.c = 0.064;
return color;
}
private get fgNegative() {
return "#d91921";
}
private get bdAccent() {
if (contrast(this.seedColor, this.bg) <= 15) {
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) <= 15) {
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.985,
c: 0,
});
color.oklch.l = 0.985;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.985,
c: 0.016,
});
color.oklch.l = 0.985;
color.oklch.c = 0.016;
return color;
}
return this.seedColor;
return color;
}
private get bdNeutral() {
if (contrast(this.seedColor, this.bg) >= -25 && !this.seedIsAchromatic) {
return setLch(this.seedColor, {
c: 0.008,
});
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) >= -25 && !this.seedIsAchromatic) {
color.oklch.c = 0.008;
return color;
}
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.15,
c: 0,
});
color.oklch.l = 0.15;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.15,
c: 0.064,
});
color.oklch.l = 0.15;
color.oklch.c = 0.064;
return color;
}
private get bdNeutralHover() {
return lighten(this.bdNeutral, 1.06);
return this.bdNeutral.clone().lighten(0.06);
}
private get bdFocus() {
let currentColor = this.seedColor;
const color = this.seedColor.clone();
currentColor = setLch(currentColor, { h: this.seedHue - 180 });
color.oklch.h = this.seedHue - 180;
if (this.seedLightness < 0.4) {
currentColor = setLch(currentColor, { l: 0.4 });
color.oklch.l = 0.4;
}
return currentColor;
return color;
}
private get bdNegative() {

View File

@ -1,11 +1,11 @@
import { contrast, lighten, setLch } from "../colorUtils";
import { ColorsAccessor } from "../ColorsAccessor";
import type Color from "colorjs.io";
import type { ColorTypes } from "colorjs.io/types/src/color";
import type { ColorModeTheme } from "./types";
export class LightModeTheme implements ColorModeTheme {
private readonly seedColor: string;
private readonly seedColor: Color;
private readonly seedLightness: number;
private readonly seedChroma: number;
private readonly seedHue: number;
@ -14,9 +14,16 @@ export class LightModeTheme implements ColorModeTheme {
private readonly seedIsVeryLight: boolean;
constructor(private color: ColorTypes) {
const { chroma, hex, hue, isAchromatic, isCold, isVeryLight, lightness } =
new ColorsAccessor(color);
this.seedColor = hex;
const {
chroma,
color: seedColor,
hue,
isAchromatic,
isCold,
isVeryLight,
lightness,
} = new ColorsAccessor(color);
this.seedColor = seedColor;
this.seedLightness = lightness;
this.seedChroma = chroma;
this.seedHue = hue;
@ -27,19 +34,22 @@ export class LightModeTheme implements ColorModeTheme {
public getColors = () => {
return {
bg: this.bg,
bgAccent: this.bgAccent,
bgAccentHover: this.bgAccentHover,
bgAccentActive: this.bgAccentActive,
bgAccentSubtleHover: this.bgAccentSubtleHover,
bgAccentSubtleActive: this.bgAccentSubtleActive,
fg: this.fg,
fgAccent: this.fgAccent,
fgOnAccent: this.fgOnAccent,
bdAccent: this.bdAccent,
bdNeutral: this.bdNeutral,
bdNeutralHover: this.bdNeutralHover,
bdFocus: this.bdFocus,
bg: this.bg.toString({ format: "hex" }),
bgAccent: this.bgAccent.toString({ format: "hex" }),
bgAccentHover: this.bgAccentHover.toString({ format: "hex" }),
bgAccentActive: this.bgAccentActive.toString({ format: "hex" }),
bgAccentSubtleHover: this.bgAccentSubtleHover.toString({ format: "hex" }),
bgAccentSubtleActive: this.bgAccentSubtleActive.toString({
format: "hex",
}),
fg: this.fg.toString({ format: "hex" }),
fgAccent: this.fgAccent.toString({ format: "hex" }),
fgOnAccent: this.fgOnAccent.toString({ format: "hex" }),
fgNegative: this.fgNegative,
bdAccent: this.bdAccent.toString({ format: "hex" }),
bdNeutral: this.bdNeutral.toString({ format: "hex" }),
bdNeutralHover: this.bdNeutralHover.toString({ format: "hex" }),
bdFocus: this.bdFocus.toString({ format: "hex" }),
bdNegative: this.bdNegative,
bdNegativeHover: this.bdNegativeHover,
};
@ -49,218 +59,243 @@ export class LightModeTheme implements ColorModeTheme {
* Background colors
*/
private get bg() {
let currentColor = this.seedColor;
const color = this.seedColor.clone();
if (this.seedIsVeryLight) {
currentColor = setLch(currentColor, {
l: 0.9,
});
color.oklch.l = 0.9;
}
if (!this.seedIsVeryLight) {
currentColor = setLch(currentColor, {
l: 0.985,
});
color.oklch.l = 0.985;
}
if (this.seedIsCold) {
currentColor = setLch(currentColor, {
c: 0.009,
});
color.oklch.c = 0.009;
}
if (!this.seedIsCold) {
currentColor = setLch(currentColor, {
c: 0.007,
});
color.oklch.c = 0.007;
}
if (this.seedIsAchromatic) {
currentColor = setLch(currentColor, {
c: 0,
});
color.oklch.c = 0;
}
return currentColor;
return color;
}
private get bgAccent() {
let currentColor = this.seedColor;
const color = this.seedColor.clone();
if (this.seedIsVeryLight) {
currentColor = setLch(currentColor, {
l: 0.975,
});
color.oklch.l = 0.975;
}
return currentColor;
return color;
}
private get bgAccentHover() {
return lighten(this.bgAccent, 1.06);
const color = this.bgAccent.clone();
if (this.seedLightness < 0.18) {
color.oklch.l = this.seedLightness + 0.3;
}
if (this.seedLightness >= 0.18 && this.seedLightness < 0.4) {
color.oklch.l = this.seedLightness + 0.15;
}
if (this.seedLightness >= 0.4 && this.seedLightness < 0.7) {
color.oklch.l = this.seedLightness + 0.05;
}
if (this.seedLightness >= 0.7) {
color.oklch.l = this.seedLightness + 0.03;
}
if (this.seedIsVeryLight) {
color.oklch.l = 0.95;
color.oklch.c = this.seedChroma * 1.15;
color.oklch.h = this.seedHue;
}
return color;
}
private get bgAccentActive() {
return lighten(this.bgAccent, 0.9);
const color = this.bgAccent.clone();
if (this.seedLightness < 0.4) {
color.oklch.l = this.seedLightness - 0.04;
}
if (this.seedLightness >= 0.4 && this.seedLightness < 0.7) {
color.oklch.l = this.seedLightness - 0.02;
}
if (this.seedLightness >= 0.7) {
color.oklch.l = this.seedLightness - 0.01;
}
if (this.seedIsVeryLight) {
color.oklch.l = 0.935;
color.oklch.c = this.seedChroma * 1.15;
color.oklch.h = this.seedHue;
}
return color;
}
// used only for generating child colors, not used as a token
private get bgAccentSubtle() {
let currentColor = this.seedColor;
const color = this.seedColor.clone();
if (this.seedLightness < 0.94) {
currentColor = setLch(currentColor, {
l: 0.94,
});
color.oklch.l = 0.94;
}
if (this.seedChroma > 0.1 && this.seedIsCold) {
currentColor = setLch(currentColor, {
c: 0.1,
});
color.oklch.c = 0.1;
}
if (this.seedChroma > 0.06 && !this.seedIsCold) {
currentColor = setLch(currentColor, {
c: 0.06,
});
color.oklch.c = 0.06;
}
if (this.seedIsAchromatic) {
currentColor = setLch(currentColor, {
c: 0,
});
color.oklch.c = 0;
}
return currentColor;
return color;
}
private get bgAccentSubtleHover() {
return lighten(this.bgAccentSubtle, 1.02);
return this.bgAccentSubtle.lighten(0.02);
}
private get bgAccentSubtleActive() {
return lighten(this.bgAccentSubtle, 0.99);
return this.bgAccentSubtle.darken(0.01);
}
/*
* Foreground colors
*/
private get fg() {
const color = this.seedColor.clone();
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.12,
c: 0,
});
color.oklch.l = 0.12;
color.oklch.c = 0;
}
return setLch(this.seedColor, {
l: 0.12,
c: 0.032,
});
color.oklch.l = 0.12;
color.oklch.c = 0.032;
return color;
}
private get fgAccent() {
if (contrast(this.seedColor, this.bg) >= -60) {
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) >= -60) {
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.25,
c: 0,
});
color.oklch.l = 0.25;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.25,
c: 0.064,
});
color.oklch.l = 0.25;
color.oklch.c = 0.064;
return color;
}
return this.seedColor;
return color;
}
private get fgOnAccent() {
if (contrast(this.seedColor, this.bg) <= -60) {
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) <= -60) {
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.985,
c: 0,
});
color.oklch.l = 0.985;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.985,
c: 0.016,
});
color.oklch.l = 0.985;
color.oklch.c = 0.016;
return color;
}
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.15,
c: 0,
});
color.oklch.l = 0.15;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.15,
c: 0.064,
});
color.oklch.l = 0.15;
color.oklch.c = 0.064;
return color;
}
private get fgNegative() {
return "#d91921";
}
/*
* Border colors
*/
private get bdAccent() {
if (contrast(this.seedColor, this.bg) >= -25) {
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) >= -25) {
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.15,
c: 0,
});
color.oklch.l = 0.15;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.15,
c: 0.064,
});
color.oklch.l = 0.15;
color.oklch.c = 0.064;
return color;
}
return this.seedColor;
return color;
}
private get bdNeutral() {
if (contrast(this.seedColor, this.bg) <= -25 && !this.seedIsAchromatic) {
return setLch(this.seedColor, {
c: 0.016,
});
const color = this.seedColor.clone();
if (this.seedColor.contrastAPCA(this.bg) <= -25 && !this.seedIsAchromatic) {
color.oklch.c = 0.016;
return color;
}
if (this.seedIsAchromatic) {
return setLch(this.seedColor, {
l: 0.15,
c: 0,
});
color.oklch.l = 0.15;
color.oklch.c = 0;
return color;
}
return setLch(this.seedColor, {
l: 0.15,
c: 0.064,
});
color.oklch.l = 0.15;
color.oklch.c = 0.064;
return color;
}
private get bdNeutralHover() {
return lighten(this.bdNeutral, 1.06);
return this.bdNeutral.clone().lighten(0.06);
}
private get bdFocus() {
let currentColor = this.seedColor;
const color = this.seedColor.clone();
currentColor = setLch(currentColor, { h: this.seedHue - 180 });
color.oklch.h = this.seedHue - 180;
if (this.seedLightness > 0.7) {
currentColor = setLch(currentColor, { l: 0.7 });
color.oklch.l = 0.7;
}
return currentColor;
return color;
}
private get bdNegative() {

View File

@ -1,6 +0,0 @@
import Color from "colorjs.io";
import type { ColorTypes } from "colorjs.io/types/src/color";
export const contrast = (color1: ColorTypes, color2: ColorTypes) => {
return Color.contrast(color1, color2, "APCA");
};

View File

@ -1,4 +0,0 @@
export { contrast } from "./contrast";
export { parse } from "./parse";
export { lighten } from "./lighten";
export { setLch } from "./setLch";

View File

@ -1,8 +0,0 @@
import { parse } from "./parse";
import type { ColorTypes } from "colorjs.io/types/src/color";
export const lighten = (color: ColorTypes, lightness: number) => {
return parse(color)
.set("oklch.l", (l) => l * lightness)
.toString({ format: "hex" });
};

View File

@ -1,6 +0,0 @@
import Color from "colorjs.io";
import type { ColorTypes } from "colorjs.io/types/src/color";
export const parse = (color: ColorTypes) => {
return new Color(color);
};

View File

@ -1,41 +0,0 @@
import type Color from "colorjs.io";
import { parse } from "./parse";
import type { ColorTypes } from "colorjs.io/types/src/color";
export const setLch = (
color: ColorTypes,
lch: {
l?: number;
c?: number;
h?: number;
},
) => {
const { c, h, l } = lch;
let currentColor = parse(color);
if (l != null) {
currentColor = setLightness(currentColor, l);
}
if (c != null) {
currentColor = setChroma(currentColor, c);
}
if (h != null) {
currentColor = setHue(currentColor, h);
}
return currentColor.toString({ format: "hex" });
};
const setLightness = (color: Color, lightness: number) => {
return color.set("oklch.l", lightness);
};
const setChroma = (color: Color, chroma: number) => {
return color.set("oklch.c", chroma);
};
const setHue = (color: Color, hue: number) => {
return color.set("oklch.h", hue);
};

View File

@ -1,4 +1,3 @@
export { contrast, parse, lighten, setLch } from "./colorUtils";
export { TokensAccessor } from "./TokensAccessor";
export { ColorsAccessor } from "./ColorsAccessor";

View File

@ -14,14 +14,10 @@
"@design-system/headless": "*",
"@design-system/theming": "*",
"@react-aria/utils": "^3.16.0",
"colorjs.io": "^0.4.3",
"eslint-plugin-storybook": "^0.6.10",
"react": "*",
"react-dom": "*"
"colorjs.io": "^0.4.3"
},
"devDependencies": {
"@types/react": "*",
"@types/react-dom": "*"
"eslint-plugin-storybook": "^0.6.10"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"

View File

@ -1,13 +1,14 @@
import React, { forwardRef } from "react";
import { Text } from "../Text";
import { Spinner } from "../Spinner";
import { StyledButton } from "./index.styled";
import type { fontFamilyTypes } from "../../utils/typography";
import type {
ButtonProps as HeadlessButtonProps,
ButtonRef as HeadlessButtonRef,
} from "@design-system/headless";
import { Text } from "../Text";
import { Spinner } from "../Spinner";
import { StyledButton } from "./index.styled";
import type { fontFamilyTypes } from "../../utils/typography";
export type ButtonVariants = "primary" | "secondary" | "tertiary";
export interface ButtonProps extends Omit<HeadlessButtonProps, "className"> {
@ -15,12 +16,11 @@ export interface ButtonProps extends Omit<HeadlessButtonProps, "className"> {
* @default primary
*/
variant?: ButtonVariants;
children?: React.ReactNode;
isDisabled?: boolean;
isLoading?: boolean;
fontFamily?: fontFamilyTypes;
isFitContainer?: boolean;
isFocused?: boolean;
iconPosition?: "start" | "end";
}
export const Button = forwardRef(
@ -37,22 +37,28 @@ export const Button = forwardRef(
...rest
} = props;
const renderChildren = () => {
if (isLoading) {
return <Spinner />;
}
return (
<Text fontFamily={fontFamily} lineClamp={1}>
{children}
</Text>
);
};
return (
<StyledButton
data-fit-container={isFitContainer}
data-focus={isFocused}
data-loading={isLoading}
data-fit-container={isFitContainer ? "" : undefined}
data-focused={isFocused}
data-loading={isLoading ? "" : undefined}
data-variant={variant}
ref={ref}
{...rest}
>
{isLoading && <Spinner />}
{!isLoading && (
<Text fontFamily={fontFamily} lineClamp={1}>
{children}
</Text>
)}
{renderChildren()}
</StyledButton>
);
},

View File

@ -15,7 +15,7 @@ export const StyledButton = styled(HeadlessButton)<ButtonProps>`
user-select: none;
// TODO: remove this when we use only flex layout
&[data-fit-container="true"] {
&[data-fit-container] {
width: 100%;
height: 100%;
}
@ -29,11 +29,11 @@ export const StyledButton = styled(HeadlessButton)<ButtonProps>`
color: var(--color-fg-on-accent);
border-color: transparent;
&.is-hovered {
&[data-hovered] {
background-color: var(--color-bg-accent-hover);
}
&.is-active {
&[data-active] {
background-color: var(--color-bg-accent-active);
}
}
@ -44,11 +44,11 @@ export const StyledButton = styled(HeadlessButton)<ButtonProps>`
border-color: var(--color-bd-accent);
border-width: var(--border-width-1);
&.is-hovered {
&[data-hovered] {
background-color: var(--color-bg-accent-subtle-hover);
}
&.is-active {
&[data-active] {
background-color: var(--color-bg-accent-subtle-active);
}
}
@ -59,22 +59,22 @@ export const StyledButton = styled(HeadlessButton)<ButtonProps>`
border-color: transparent;
border-width: 0;
&.is-hovered {
&[data-hovered] {
background: var(--color-bg-accent-subtle-hover);
}
&.is-active {
&[data-active] {
background: var(--color-bg-accent-subtle-active);
}
}
// we don't use :focus-visible because not all browsers (safari) have it yet
&:not([data-loading]).focus-ring,
&[data-focused]:not([data-loading]),
&[data-focus="true"] {
box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-bd-focus);
}
&.is-disabled {
&[data-disabled] {
pointer-events: none;
opacity: var(--opacity-disabled);
}

View File

@ -126,7 +126,7 @@ Checkbox is a component that allows the user to select one or more options from
<Canvas>
<Story
name="State - Custom Icon"
name="Custom Icon"
args={{
children: "Custom Icon",
icon: <EmotionHappyLineIcon />,

View File

@ -8,9 +8,7 @@ import type {
import { Text } from "../Text";
import { StyledCheckbox } from "./index.styled";
export type CheckboxProps = HeadlessCheckboxProps & {
labelPosition?: "left" | "right";
};
export type CheckboxProps = HeadlessCheckboxProps;
export const Checkbox = forwardRef(
(props: CheckboxProps, ref: HeadlessCheckboxRef) => {
@ -18,7 +16,11 @@ export const Checkbox = forwardRef(
return (
<StyledCheckbox labelPosition={labelPosition} ref={ref} {...rest}>
{children && <Text className="label">{children}</Text>}
{children && (
<div className="label">
<Text>{children}</Text>
</div>
)}
</StyledCheckbox>
);
},

View File

@ -9,24 +9,34 @@ export const labelStyles = css<Pick<CheckboxProps, "labelPosition">>`
position: relative;
display: flex;
gap: var(--spacing-2);
width: 100%;
cursor: pointer;
${({ labelPosition }) => css`
justify-content: ${labelPosition === "left" ? "space-between" : undefined};
flex-direction: ${labelPosition === "left" ? "row-reverse" : "row"};
`};
.label {
&[data-label] {
min-height: calc(5 * var(--sizing-root-unit));
display: flex;
align-items: center;
}
/**
* ----------------------------------------------------------------------------
* DISABLED
*-----------------------------------------------------------------------------
*/
&[data-disabled] {
pointer-events: none;
opacity: var(--opacity-disabled);
}
`;
export const StyledCheckbox = styled(HeadlessCheckbox)<CheckboxProps>`
${labelStyles}
.icon {
[data-icon] {
width: calc(5 * var(--sizing-root-unit));
height: calc(5 * var(--sizing-root-unit));
border-width: var(--border-width-1);
@ -41,7 +51,7 @@ export const StyledCheckbox = styled(HeadlessCheckbox)<CheckboxProps>`
flex-shrink: 0;
}
&.is-hovered:not(.is-disabled) .icon {
&[data-hovered]:not([data-disabled]) [data-icon] {
border-color: var(--color-bd-neutral-hover);
}
@ -50,39 +60,26 @@ export const StyledCheckbox = styled(HeadlessCheckbox)<CheckboxProps>`
* CHECKED AND INDETERMINATE - BUT NOT DISABLED
*-----------------------------------------------------------------------------
*/
&.is-checked .icon,
&.is-indeterminate .icon {
&[data-state="checked"] [data-icon],
&[data-state="indeterminate"] [data-icon] {
background-color: var(--color-bg-accent);
border-color: var(--color-bg-accent);
color: var(--color-fg-on-accent);
}
&.is-hovered.is-checked:not(.is-disabled) .icon,
&.is-hovered.is-indeterminate:not(.is-disabled) .icon {
&[data-hovered][data-state="checked"]:not([data-disabled]) [data-icon],
&[data-hovered][data-state="indeterminate"]:not([data-disabled]) [data-icon] {
border-color: var(--color-bg-accent-hover);
background-color: var(--color-bg-accent-hover);
color: var(--color-fg-on-accent);
}
/**
* ----------------------------------------------------------------------------
* DISABLED
*-----------------------------------------------------------------------------
*/
&.is-disabled {
cursor: not-allowed;
}
&.is-disabled {
opacity: var(--opacity-disabled);
}
/**
* ----------------------------------------------------------------------------
* FOCUS
*-----------------------------------------------------------------------------
*/
&.is-focused .icon {
&[data-focused] [data-icon] {
box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-bd-focus);
}
@ -91,11 +88,11 @@ export const StyledCheckbox = styled(HeadlessCheckbox)<CheckboxProps>`
* ERROR ( INVALID )
*-----------------------------------------------------------------------------
*/
&.is-invalid .icon {
&[data-invalid] [data-icon] {
border-color: var(--color-bd-negative);
}
&.is-hovered.is-invalid .icon {
&[data-hovered][data-invalid] [data-icon] {
border-color: var(--color-bd-negative-hover);
}
`;

View File

@ -0,0 +1,123 @@
import { Canvas, Meta, Story, ArgsTable } from "@storybook/addon-docs";
import { CheckboxGroup } from "./";
import { Checkbox } from "../Checkbox";
<Meta
title="Design-system/widgets/CheckboxGroup"
component={CheckboxGroup}
parameters={{
width: "200px",
}}
args={{
label: "Checkbox Group",
defaultValue: ["value-1"],
children: (
<>
<Checkbox value="value-1">Value 1</Checkbox>
<Checkbox value="value-2">Value 2</Checkbox>
</>
),
}}
/>
export const Template = (args, { globals: { fontFamily } }) => (
<CheckboxGroup {...args} />
);
# Checkbox Group
Checkbox Group is a group of checkboxes that can be selected together.
<Canvas>
<Story name="Checkbox Group">{Template.bind({})}</Story>
</Canvas>
# Orientation
<Canvas>
<Story
args={{
orientation: "vertical",
}}
name="Orientation - Vertical"
>
{Template.bind({})}
</Story>
<Story
args={{
orientation: "horizontal",
}}
name="Orientation - Horizontal"
>
{Template.bind({})}
</Story>
</Canvas>
# Emphasized
<Canvas>
<Story
args={{
isEmphasized: true,
}}
name="Is Emphasised"
>
{Template.bind({})}
</Story>
</Canvas>
# Label Position and Alignment
<Canvas>
<Story
args={{
labelPosition: "side",
labelWidth: "100px",
errorMessage: "This is a description",
}}
name="Label Position - Side"
>
{Template.bind({})}
</Story>
</Canvas>
# Is Disabled
<Canvas>
<Story
args={{
isDisabled: true,
}}
name="Is Disabled"
>
{Template.bind({})}
</Story>
</Canvas>
# Is Required
<Canvas>
<Story
args={{
isRequired: true,
}}
name="Is Required"
>
{Template.bind({})}
</Story>
</Canvas>
# Invalid State
<Canvas>
<Story
args={{
validationState: "invalid",
errorMessage: "This is a error message",
}}
name="Invalid State"
>
{Template.bind({})}
</Story>
</Canvas>

View File

@ -0,0 +1,31 @@
import React, { forwardRef } from "react";
import type {
CheckboxGroupRef as HeadlessCheckboxGroupRef,
CheckboxGroupProps as HeadlessCheckboxGroupProps,
} from "@design-system/headless";
import { Text } from "../Text";
import { StyledCheckboxGroup } from "./index.styled";
export interface CheckboxGroupProps extends HeadlessCheckboxGroupProps {
className?: string;
labelWidth?: string;
}
export const CheckboxGroup = forwardRef(
(props: CheckboxGroupProps, ref: HeadlessCheckboxGroupRef) => {
const { errorMessage, label, ...rest } = props;
const wrappedErrorMessage = errorMessage && <Text>{errorMessage}</Text>;
const wrappedLabel = label && <Text>{label}</Text>;
return (
<StyledCheckboxGroup
errorMessage={wrappedErrorMessage}
label={wrappedLabel}
ref={ref}
{...rest}
/>
);
},
);

View File

@ -0,0 +1,11 @@
import styled from "styled-components";
import { CheckboxGroup as HeadlessCheckboxGroup } from "@design-system/headless";
import { fieldStyles } from "../../styles/fieldStyles";
import type { CheckboxGroupProps } from "./CheckboxGroup";
export const StyledCheckboxGroup = styled(
HeadlessCheckboxGroup,
)<CheckboxGroupProps>`
${fieldStyles}
`;

View File

@ -0,0 +1,2 @@
export { CheckboxGroup } from "./CheckboxGroup";
export type { CheckboxGroupProps } from "./CheckboxGroup";

View File

@ -1,4 +1,8 @@
// components
export * from "./components/Button";
export * from "./components/Checkbox";
export * from "./components/Text";
export * from "./components/CheckboxGroup";
// utils
export * from "./utils/typography";

View File

@ -0,0 +1,88 @@
import { css } from "styled-components";
import type { LabelProps as HeadlessLabelProps } from "@design-system/headless";
type FieldStylesProps = Pick<
HeadlessLabelProps,
"labelPosition" | "isEmphasized"
> & {
labelWidth?: string;
};
// NOTE: these field styles are used in every input component that has a label
// for e.g input, select, checkbox group, toggle group, radio group, etc
export const fieldStyles = css<FieldStylesProps>`
&[data-field] {
display: flex;
flex-direction: column;
gap: var(--spacing-3);
&[data-position="side"] {
flex-direction: row;
}
&[data-disabled] {
cursor: not-allowed;
opacity: var(--opacity-disabled);
& > * {
pointer-events: none;
}
}
}
/**
* ----------------------------------------------------------------------------
* LABEL
*-----------------------------------------------------------------------------
*/
& [data-field-label] {
display: flex;
align-items: center;
gap: var(--spacing-1);
height: fit-content;
color: var(--color-fg);
font-weight: ${({ isEmphasized }) => (isEmphasized ? "bold" : "normal")};
// when the label is on the side, we need to make sure the label is aligned
&[data-position="side"] {
min-height: calc(5 * var(--sizing-root-unit));
width: ${({ labelWidth }) => labelWidth};
}
}
/**
* ----------------------------------------------------------------------------
* REQUIRED ICON
*-----------------------------------------------------------------------------
*/
& [data-field-necessity-indicator-icon] {
width: var(--spacing-2);
height: var(--spacing-2);
}
/**
* ----------------------------------------------------------------------------
* ERROR TEXT
*-----------------------------------------------------------------------------
*/
& [data-field-error-text] {
display: flex;
align-items: center;
color: var(--color-fg-negative);
}
/**
* ----------------------------------------------------------------------------
* FIELD GROUP
*-----------------------------------------------------------------------------
*/
& [data-field-group] {
gap: var(--spacing-2);
display: flex;
flex-direction: column;
&[data-orientation="horizontal"] {
flex-direction: row;
}
}
`;

View File

@ -38,8 +38,6 @@
"@capsizecss/core": "^3.1.0",
"@capsizecss/metrics": "^1.0.1",
"colorjs.io": "^0.4.3",
"react": "^17.0.2",
"react-docgen-typescript": "^2.2.2",
"react-dom": "^17.0.2"
"react-docgen-typescript": "^2.2.2"
}
}

View File

@ -53,9 +53,12 @@
gapiLoaded = () => {
window.googleAPIsLoaded = true;
}
onError = () => {
window.googleAPIsLoaded = false;
};
</script>
<!-- Adding this Library to access google file picker API in case of limiting google sheet access -->
<script async defer id="googleapis" src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
<script async defer id="googleapis" src="https://apis.google.com/js/api.js" onload="gapiLoaded()" onerror="onError()"></script>
</head>
<body class="appsmith-light-theme">
@ -144,8 +147,6 @@
smartLook: {
id: parseConfig("__APPSMITH_SMART_LOOK_ID__"),
},
enableGoogleOAuth: parseConfig("__APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__"),
enableGithubOAuth: parseConfig("__APPSMITH_OAUTH2_GITHUB_CLIENT_ID__"),
disableLoginForm: parseConfig("__APPSMITH_FORM_LOGIN_DISABLED__"),
disableSignup: parseConfig("__APPSMITH_SIGNUP_DISABLED__"),
enableRapidAPI: parseConfig("__APPSMITH_MARKETPLACE_ENABLED__"),

View File

@ -0,0 +1,33 @@
import { getQueryStringfromObject } from "./RouteBuilder";
describe("Route builder", () => {
describe("tests getQueryStringfromObject", () => {
const cases = [
{
index: 0,
input: { id: 0, a: "b&c ltd" },
expected: "?id=0&a=b%26c%20ltd",
},
{ index: 1, input: {}, expected: "" },
{
index: 2,
input: { rando: "রিমিল" },
expected: "?rando=%E0%A6%B0%E0%A6%BF%E0%A6%AE%E0%A6%BF%E0%A6%B2",
},
{
index: 3,
input: { a1: "1234*&^%~`<>:';,./?" },
expected: "?a1=1234*%26%5E%25~%60%3C%3E%3A'%3B%2C.%2F%3F",
},
{ index: 4, input: { isSignedIn: false }, expected: "?isSignedIn=false" },
];
test.each(cases.map((x) => [x.index, x.input, x.expected]))(
"test case %d",
(_, input, expected) => {
const result = getQueryStringfromObject(input as any);
expect(result).toStrictEqual(expected);
},
);
});
});

View File

@ -12,6 +12,7 @@ import type {
ApplicationPayload,
Page,
} from "@appsmith/constants/ReduxActionConstants";
import { isNil } from "lodash";
export type URLBuilderParams = {
suffix?: string;
@ -44,9 +45,11 @@ export function getQueryStringfromObject(
const queryParams: string[] = [];
if (paramKeys) {
paramKeys.forEach((paramKey: string) => {
const value = params[paramKey];
if (paramKey && value) {
queryParams.push(`${paramKey}=${value}`);
if (!isNil(params[paramKey])) {
const value = encodeURIComponent(params[paramKey]);
if (paramKey && value) {
queryParams.push(`${paramKey}=${value}`);
}
}
});
}

View File

@ -17,6 +17,21 @@ export const toggleInOnboardingWidgetSelection = (payload: boolean) => {
};
};
export const removeFirstTimeUserOnboardingApplicationId = (
applicationId: string,
) => {
return {
type: ReduxActionTypes.REMOVE_FIRST_TIME_USER_ONBOARDING_APPLICATION_ID,
payload: applicationId,
};
};
export const disableStartSignpostingAction = () => {
return {
type: ReduxActionTypes.DISABLE_START_SIGNPOSTING,
};
};
export const firstTimeUserOnboardingInit = (
applicationId: string | undefined,
pageId: string,

View File

@ -68,6 +68,10 @@ export const updateUserDetails = (payload: UpdateUserRequest) => ({
payload,
});
export const updateIntercomConsent = () => ({
type: ReduxActionTypes.UPDATE_USER_INTERCOM_CONSENT,
});
export const updatePhoto = (payload: {
file: File;
callback?: (id: string) => void;

View File

@ -49,7 +49,13 @@ export interface ExecuteActionRequest extends APIRequest {
params?: Property[];
paginationField?: PaginationField;
viewMode: boolean;
paramProperties: Record<string, string | Record<string, string[]>>;
paramProperties: Record<
string,
| string
| Record<string, Array<string>>
| Record<string, string>
| Record<string, Record<string, Array<string>>>
>;
}
export type ExecuteActionResponse = ApiResponse & {

View File

@ -7,3 +7,4 @@
@import "./roboto/roboto.css";
@import "./rubik/rubik.css";
@import "./ubuntu/ubuntu.css";
@import "./twemoji/twemoji.css";

Some files were not shown because too many files have changed in this diff Show More