Merge pull request #22936 from appsmithorg/ci/release-frozen-1.9.18
ci: Promotional PR
This commit is contained in:
commit
3cb8d21c1b
25
.github/workflows/CypressAddKnownfailedtests.yml
vendored
25
.github/workflows/CypressAddKnownfailedtests.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
43
README.md
43
README.md
|
|
@ -159,8 +159,8 @@ Lets build great software together.
|
|||
[](https://github.com/Nikhil-Nandagopal)
|
||||
[](https://github.com/mohanarpit)
|
||||
[](https://github.com/hetunandu)
|
||||
[](https://github.com/trishaanand)
|
||||
[](https://github.com/sharat87)
|
||||
[](https://github.com/trishaanand)
|
||||
[](https://github.com/riodeuno)
|
||||
[](https://github.com/vicky-primathon)
|
||||
[](https://github.com/akash-codemonk)
|
||||
|
|
@ -171,8 +171,8 @@ Lets build great software together.
|
|||
[](https://github.com/AnaghHegde)
|
||||
[](https://github.com/NandanAnantharamu)
|
||||
[](https://github.com/arunvjn)
|
||||
[](https://github.com/nayan-rafiq)
|
||||
[](https://github.com/Aishwarya-U-R)
|
||||
[](https://github.com/nayan-rafiq)
|
||||
[](https://github.com/abhvsn)
|
||||
[](https://github.com/jsartisan)
|
||||
[](https://github.com/ankitakinger)
|
||||
|
|
@ -183,8 +183,8 @@ Lets build great software together.
|
|||
[](https://github.com/sbalaji1192)
|
||||
[](https://github.com/Irongade)
|
||||
[](https://github.com/SatishGandham)
|
||||
[](https://github.com/yatinappsmith)
|
||||
[](https://github.com/prsidhu)
|
||||
[](https://github.com/yatinappsmith)
|
||||
[](https://github.com/sidhantgoel)
|
||||
[](https://github.com/somangshu)
|
||||
[](https://github.com/ApekshaBhosale)
|
||||
|
|
@ -193,47 +193,45 @@ Lets build great software together.
|
|||
[](https://github.com/Parthvi12)
|
||||
[](https://github.com/marks0351)
|
||||
[](https://github.com/albinAppsmith)
|
||||
[](https://github.com/ashit-rath)
|
||||
[](https://github.com/sarojsarab)
|
||||
[](https://github.com/AmanAgarwal041)
|
||||
[](https://github.com/eco-monk)
|
||||
[](https://github.com/ashit-rath)
|
||||
[](https://github.com/ayushpahwa)
|
||||
[](https://github.com/sarojsarab)
|
||||
[](https://github.com/eco-monk)
|
||||
[](https://github.com/berzerkeer)
|
||||
[](https://github.com/areyabhishek)
|
||||
[](https://github.com/keyurparalkar)
|
||||
[](https://github.com/rimildeyjsr)
|
||||
[](https://github.com/vishnu-gp)
|
||||
[](https://github.com/berzerkeer)
|
||||
[](https://github.com/sneha122)
|
||||
[](https://github.com/ChandanBalajiBP)
|
||||
[](https://github.com/pratapaprasanna)
|
||||
[](https://github.com/megaconfidence)
|
||||
[](https://github.com/sum35h)
|
||||
[](https://github.com/nsarupr)
|
||||
[](https://github.com/vihar)
|
||||
[](https://github.com/subrata71)
|
||||
[](https://github.com/dhruvikn)
|
||||
[](https://github.com/nsarupr)
|
||||
[](https://github.com/Vijetha-Kaja)
|
||||
[](https://github.com/dhruvikn)
|
||||
[](https://github.com/tanvibhakta)
|
||||
[](https://github.com/NilanshBansal)
|
||||
[](https://github.com/sondermanish)
|
||||
[](https://github.com/prapullac)
|
||||
[](https://github.com/Druthi)
|
||||
[](https://github.com/vsvamsi1)
|
||||
[](https://github.com/rohitagarwal88)
|
||||
[](https://github.com/Druthi)
|
||||
[](https://github.com/ravikp7)
|
||||
[](https://github.com/PiyushPushkar02)
|
||||
[](https://github.com/rajatagrawal)
|
||||
[](https://github.com/KelvinOm)
|
||||
[](https://github.com/Pranay105)
|
||||
[](https://github.com/PiyushPushkar02)
|
||||
[](https://github.com/rohitagarwal88)
|
||||
[](https://github.com/ankitsrivas14)
|
||||
[](https://github.com/Pranay105)
|
||||
[](https://github.com/ramsaptami)
|
||||
[](https://github.com/sanveer-osahan)
|
||||
[](https://github.com/ichik)
|
||||
[](https://github.com/rahulbarwal)
|
||||
[](https://github.com/rohan-arthur)
|
||||
[](https://github.com/sanveer-osahan)
|
||||
[](https://github.com/dipyamanbiswas07)
|
||||
[](https://github.com/vivonk)
|
||||
[](https://github.com/rahulbarwal)
|
||||
[](https://github.com/kocharrahul7)
|
||||
[](https://github.com/rohan-arthur)
|
||||
[](https://github.com/AS-Laguna)
|
||||
[](https://github.com/jacquesikot)
|
||||
[](https://github.com/RakshaKShetty)
|
||||
|
|
@ -265,7 +263,7 @@ Lets build great software together.
|
|||
[](https://github.com/AnandiKulkarni)
|
||||
[](https://github.com/momcilo-appsmith)
|
||||
[](https://github.com/shwetha-ramesh)
|
||||
[](https://github.com/vasanth-appsmith)
|
||||
[](https://github.com/vasanthappsmith)
|
||||
[](https://github.com/parth-appsmith)
|
||||
[](https://github.com/Richarex)
|
||||
[](https://github.com/chandannkumar)
|
||||
|
|
@ -285,6 +283,7 @@ Lets build great software together.
|
|||
[](https://github.com/abhiappsmith)
|
||||
[](https://github.com/deepikaappsmith)
|
||||
[](https://github.com/tkAppsmith)
|
||||
[](https://github.com/prapullc)
|
||||
[](https://github.com/rishabhsaxena)
|
||||
[](https://github.com/wmdev0808)
|
||||
[](https://github.com/techbhavin)
|
||||
|
|
@ -295,6 +294,7 @@ Lets build great software together.
|
|||
[](https://github.com/rashmigowda55)
|
||||
[](https://github.com/ankurrsinghal)
|
||||
[](https://github.com/geekup-legodevops)
|
||||
[](https://github.com/vihar)
|
||||
[](https://github.com/danieldare)
|
||||
[](https://github.com/Nikhil-Curefit)
|
||||
[](https://github.com/souma-ghosh)
|
||||
|
|
@ -303,6 +303,7 @@ Lets build great software together.
|
|||
[](https://github.com/leotom2000)
|
||||
[](https://github.com/Adityaacharya1807)
|
||||
[](https://github.com/RashmiNagarajp)
|
||||
[](https://github.com/prapullac)
|
||||
[](https://github.com/kaushik94)
|
||||
[](https://github.com/akshayrangasaid)
|
||||
[](https://github.com/mojtab23)
|
||||
|
|
@ -350,6 +351,7 @@ Lets build great software together.
|
|||
[](https://github.com/nuwan94)
|
||||
[](https://github.com/OmkarPh)
|
||||
[](https://github.com/parthiv11)
|
||||
[](https://github.com/priyanka-mahour)
|
||||
[](https://github.com/rafaeelaudibert)
|
||||
[](https://github.com/samyakjain10)
|
||||
[](https://github.com/Jain-Sanchit)
|
||||
|
|
@ -373,6 +375,7 @@ Lets build great software together.
|
|||
[](https://github.com/apoorv-mishra)
|
||||
[](https://github.com/anvaravind)
|
||||
[](https://github.com/ari-hacks)
|
||||
[](https://github.com/arunstar)
|
||||
[](https://github.com/ashwanisindhu1)
|
||||
[](https://github.com/Caitlin-Fotheringham)
|
||||
[](https://github.com/Chiradeep-Banik)
|
||||
|
|
@ -382,6 +385,7 @@ Lets build great software together.
|
|||
[](https://github.com/DiptoChakrabarty)
|
||||
[](https://github.com/felixsuarez0727)
|
||||
[](https://github.com/gitstart)
|
||||
[](https://github.com/harshmange44)
|
||||
[](https://github.com/ishaanmehta4)
|
||||
[](https://github.com/iamakulov)
|
||||
[](https://github.com/jarimayenburg)
|
||||
|
|
@ -407,7 +411,6 @@ Lets build great software together.
|
|||
[](https://github.com/paususe)
|
||||
[](https://github.com/neok)
|
||||
[](https://github.com/sanchezpili6)
|
||||
[](https://github.com/priyanka-mahour)
|
||||
[](https://github.com/pushkar1393)
|
||||
[](https://github.com/imor)
|
||||
[](https://github.com/ricardocarrola)
|
||||
|
|
|
|||
1972
app/client/cypress/fixtures/AllWidgetsDsl.json
Normal file
1972
app/client/cypress/fixtures/AllWidgetsDsl.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1200
app/client/cypress/fixtures/mobileViewScrollDsl.json
Normal file
1200
app/client/cypress/fixtures/mobileViewScrollDsl.json
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -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");
|
||||
// });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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')",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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}}");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
});
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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", () => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
() =>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
83
app/client/cypress/support/Pages/Onboarding.ts
Normal file
83
app/client/cypress/support/Pages/Onboarding.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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() +
|
||||
|
|
|
|||
|
|
@ -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") =>
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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---//
|
||||
|
|
|
|||
|
|
@ -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}';
|
||||
|
|
|
|||
|
|
@ -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}';
|
||||
|
|
|
|||
|
|
@ -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}';
|
||||
|
|
|
|||
|
|
@ -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__"),
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import React from "react";
|
||||
|
||||
import type { CheckboxGroupState } from "@react-stately/checkbox";
|
||||
|
||||
export const CheckboxGroupContext =
|
||||
React.createContext<CheckboxGroupState | null>(null);
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
export { Checkbox } from "./Checkbox";
|
||||
export { CheckboxGroup } from "./CheckboxGroup";
|
||||
export type { CheckboxProps, CheckboxRef } from "./Checkbox";
|
||||
export type { CheckboxGroupProps, CheckboxGroupRef } from "./CheckboxGroup";
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -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>
|
||||
);
|
||||
});
|
||||
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./Field";
|
||||
export type { FieldProps, FieldRef } from "./Field";
|
||||
export type { LabelProps } from "./Label";
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
// components
|
||||
export * from "./components/Button";
|
||||
export * from "./components/Checkbox";
|
||||
export * from "./components/Field";
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
};
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
export { contrast } from "./contrast";
|
||||
export { parse } from "./parse";
|
||||
export { lighten } from "./lighten";
|
||||
export { setLch } from "./setLch";
|
||||
|
|
@ -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" });
|
||||
};
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
export { contrast, parse, lighten, setLch } from "./colorUtils";
|
||||
export { TokensAccessor } from "./TokensAccessor";
|
||||
export { ColorsAccessor } from "./ColorsAccessor";
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 />,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -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}
|
||||
`;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { CheckboxGroup } from "./CheckboxGroup";
|
||||
export type { CheckboxGroupProps } from "./CheckboxGroup";
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__"),
|
||||
|
|
|
|||
33
app/client/src/RouteBuilder.test.ts
Normal file
33
app/client/src/RouteBuilder.test.ts
Normal 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);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -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}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 & {
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue
Block a user