From fd79d766180b137a0e23d53892e4b14840eec418 Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Tue, 12 Mar 2024 13:48:52 +0530 Subject: [PATCH 01/25] Updated Label Config --- .github/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/config.json b/.github/config.json index c67bf7d48b..ebaa14d1a8 100644 --- a/.github/config.json +++ b/.github/config.json @@ -1 +1 @@ -{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Error Handling":{"conditions":[],"requires":1},"Team Managers Pod":{"conditions":[{"label":"SSO","type":"hasLabel","value":true},{"label":"RBAC","type":"hasLabel","value":true},{"label":"Audit Logs","type":"hasLabel","value":true},{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"Admin Settings","type":"hasLabel","value":true},{"label":"Workspace settings","type":"hasLabel","value":true}],"requires":1},"New Developers Pod":{"conditions":[{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Telemetry","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"IDE","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"In App Comms","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true}],"requires":1},"BE Coders Pod":{"conditions":[{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Data Platform Pod","type":"hasLabel","value":true},{"label":"Integrations Pod","type":"hasLabel","value":true}],"requires":1},"FE Coders Pod":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Debugger","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Error Handling","type":"hasLabel","value":true}],"requires":1},"App Viewers Pod":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"reallabel","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Branding","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Custom widgets","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true}],"requires":1},"UI Builders Pod":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Responsive Canvas","type":"hasLabel","value":true},{"label":"Responsive Widget","type":"hasLabel","value":true},{"label":"Responsive Viewport","type":"hasLabel","value":true},{"label":"Spacing","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"User Education Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true}],"requires":1},"Design System Pod":{"conditions":[{"label":"Design System Pod","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true}],"requires":1},"Data Platform Pod":{"conditions":[{"label":"Datasource Environments","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"Page load executions","type":"hasLabel","value":true},{"label":"DSL Update","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"DocumentDB","type":"hasLabel","value":true},{"label":"Multiple Environments","type":"hasLabel","value":true},{"label":"Platformization","type":"hasLabel","value":true},{"label":"Custom environments","type":"hasLabel","value":true},{"label":"Schema","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true}],"requires":1},"Integrations Pod":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"Onboarding","type":"hasLabel","value":true},{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"Welcome Screen","type":"hasLabel","value":true},{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Activation - learnability","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true}],"requires":1},"Git Pod":{"conditions":[{"label":"Git Version Control","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true},{"label":"Fork App","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true}],"requires":1},"Mobile Pod":{"conditions":[],"requires":1},"Billing & Usage Pod":{"conditions":[{"label":"CE Instance","type":"hasLabel","value":true},{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing Integrations","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"In-app ramps","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"Appsmith Business Cloud","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Embedding Apps","type":"hasLabel","value":true},{"label":"TM_BU","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"Invite users","type":"hasLabel","value":true},{"label":"Home Page","type":"hasLabel","value":true},{"label":"1-click upgrade","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Preview mode","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true}],"requires":1},"Appsmith Labs":{"conditions":[{"label":"AI","type":"hasLabel","value":true},{"label":"Knowledge Retrieval","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows","type":"hasLabel","value":true}],"requires":1},"Modules pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true}],"requires":1},"Templates Pod":{"conditions":[{"label":"Templates","type":"hasLabel","value":true},{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true}],"requires":1},"Widget design system POD":{"conditions":[{"label":"App Theming","type":"hasLabel","value":true},{"label":"Widget Styling","type":"hasLabel","value":true},{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Widget design system POD","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"9c0c8e","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"30c76d","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"Onboarding":{"color":"30c76d","name":"Onboarding","description":"Issues related to onboarding new developers"},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Widget Styling":{"color":"905420","name":"Widget Styling","description":"all about widget styling"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"App Viewers Pod":{"color":"cd8ef9","name":"App Viewers Pod","description":"This label assigns issues to the app viewers pod"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"30c76d","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Team Managers Pod":{"color":"bddb81","name":"Team Managers Pod","description":"Issues that team managers care about for the security and efficiency of their teams"},"Import-Export-App":{"color":"15076d","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"10b5ce","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"30c76d","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"IDE":{"color":"61b2ee","name":"IDE","description":"Issues related to the IDE"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Git Version Control":{"color":"858172","name":"Git Version Control","description":"Issues related to version control"},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"a2e2f9","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Debugger":{"color":"e79062","name":"Debugger","description":"Issues related to the debugger"},"Quick effort":{"color":"95ED65","name":"Quick effort","description":"Something that'll take a few hours to build"},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"UI Builders Pod":{"color":"517fba","name":"UI Builders Pod","description":"Issues that UI Builders face using appsmith"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"In App Comms":{"name":"In App Comms","description":"Issues around communication with appsmith instances","color":"463cca"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"BE Coders Pod":{"color":"5d9848","name":"BE Coders Pod","description":"Issues related to users writing code to fetch and update data"},"FE Coders Pod":{"color":"a7effc","name":"FE Coders Pod","description":"Issues related to users writing javascript in appsmith"},"New Developers Pod":{"color":"6310da","name":"New Developers Pod","description":"Issues that new developers face while exploring the IDE"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"30c76d"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Responsive Viewport":{"color":"d12d2e","name":"Responsive Viewport","description":"Issues seen on different viewports like mobile"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"User Education Pod":{"name":"User Education Pod","description":"Issues related to user education","color":"1799b0"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Embedding Apps":{"name":"Embedding Apps","description":"Issues related to embedding","color":"30c76d"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"ef9c9d"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"50559d"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"30c76d"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"App Theming":{"name":"App Theming","description":"Items that are related to the App level theming controls epic","color":"905420"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":"bf019b"},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Templates":{"name":"Templates","description":"Issues related to templates","color":"b893f6"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"RBAC":{"name":"RBAC","description":"Issues, requests and enhancements around RBAC.","color":"9211c3"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Design System Pod":{"name":"Design System Pod","description":"Appsmith design system related issues","color":"706f03"},"ABAC":{"color":"e009a5","name":"ABAC","description":"User permissions and access controls"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"60885f"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"bc0cba"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"e4d966"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"418fa4"},"Branding":{"name":"Branding","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"7aaaf1"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"Audit Logs":{"name":"Audit Logs","description":"Audit trails to ensure data security","color":"f3fd62"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Data Platform Pod":{"name":"Data Platform Pod","description":"Issues related to the underlying data platform","color":"3f8c3a"},"Integrations Pod":{"name":"Integrations Pod","description":"Issues related to a specific integration","color":"5dbbb1"},"Datasource Environments":{"name":"Datasource Environments","description":"Issues related to datasource environments","color":"bb7a14"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"418fa4","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"6a5b42"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"c7da7a"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"e4d966"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"e4d966"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"e4d966"},"Page load executions":{"name":"Page load executions","description":"Issues related to page load execution","color":"5696b2"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Git Pod":{"name":"Git Pod","description":"Anything related to git sync","color":"2e5ba4"},"Mobile Pod":{"name":"Mobile Pod","description":"All issues related to mobile responsiveness","color":"6c97fd"},"Responsive Widget":{"name":"Responsive Widget","description":"All issues related to widget responsiveness","color":"d12d2e"},"Responsive Canvas":{"name":"Responsive Canvas","description":"All issues related to canvas responsiveness","color":"45a0a8"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Spacing":{"name":"Spacing","description":"All issue related to spacing between widgets in auto layout","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Error Handling":{"name":"Error Handling","description":"Issues related to error handling","color":"4e1872"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"434a3a"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"c476eb"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"Billing & Usage Pod":{"name":"Billing & Usage Pod","description":"Issues pertaining to licensing, billing, usage across self serve and enterprise customers","color":"256808"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"8154df"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"CE Instance":{"name":"CE Instance","description":"For all issues relating to usage, licensing or billing on the CE instance","color":"d2bc40"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"Billing Integrations":{"name":"Billing Integrations","description":"For all issues relating to 3P integrations Appsmith is using for billing & usage","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Appsmith Business Cloud":{"name":"Appsmith Business Cloud","description":"Issues related to our business cloud offering","color":"89bb6c"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"In-app ramps":{"name":"In-app ramps","description":"For all tasks/issues relating to adding in-app ramps in the community edition of the product","color":"8abae0"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"8d8a09"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"61a852"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"DocumentDB":{"name":"DocumentDB","description":"Issues related to support DocumentDB in Appsmith Data layer","color":"2c8b56"},"Multiple Environments":{"name":"Multiple Environments","description":"Issues or tasks related to multiple environments","color":"4e972b"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"75c4ce"},"Custom environments":{"name":"Custom environments","description":"Issues with creating or working with custom environments","color":"2137d6"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"144206"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Schema":{"name":"Schema","description":"Issues related to database schema","color":"c470c2"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"722bf0"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"IDE Pod":{"name":"IDE Pod","description":"https://app.zenhub.com/workspaces/new-developers-pod-60507ad1d4b98d00150a2858/board","color":"d3d248"},"TM_BU":{"name":"TM_BU","description":"The issues on Team Manager which needs to be taken up by Billing & Usage","color":"198cdf"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Appsmith Labs":{"name":"Appsmith Labs","description":"All things related to AI and other new initiatives ","color":"712d51"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":"23e6d6"},"Workflows Pod":{"name":"Workflows Pod","description":"For all issues related to the Workflows feature","color":"a86802"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"Knowledge Retrieval":{"name":"Knowledge Retrieval","description":"All issues related to knowledge retrieval on Appsmith AI","color":"a36890"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"1-click upgrade":{"name":"1-click upgrade","description":"For all issues/tasks related to 1-click upgrade & downgrade project","color":"51b5ff"},"Activation - learnability":{"name":"Activation - learnability","description":"Activation - learnability","color":"96fc76"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Modules pod":{"name":"Modules pod","description":"issues that belong to the modules pod","color":"4c6329"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package":{"name":"Package","description":"Issues related to packages","color":"2ad485"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Templates Pod":{"name":"Templates Pod","description":"Issues related to Templates","color":"e7b3b9"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"cce8e7"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"3fb8f2"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":""},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"4c1858"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Admin Settings":{"color":"32a316","name":"Admin Settings","description":"Issues related to admin settings"},"Workspace settings":{"name":"Workspace settings","description":"Issues related to workspace settings","color":"47d1ad"},"Page Management":{"color":"e17a68","name":"Page Management","description":"Issues related to configuring pages"},"Test":{"name":"Test","description":"","color":"33515b"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Workflows":{"name":"Workflows","description":"","color":"1b89db"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"8e3c7a"},"Widget design system POD":{"name":"Widget design system POD","description":"","color":"bbeecd"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"}},"success":true} \ No newline at end of file +{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Error Handling":{"conditions":[],"requires":1},"Team Managers Pod":{"conditions":[{"label":"SSO","type":"hasLabel","value":true},{"label":"RBAC","type":"hasLabel","value":true},{"label":"Audit Logs","type":"hasLabel","value":true},{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"Admin Settings","type":"hasLabel","value":true},{"label":"Workspace settings","type":"hasLabel","value":true}],"requires":1},"New Developers Pod":{"conditions":[{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Telemetry","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"IDE","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"In App Comms","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true}],"requires":1},"BE Coders Pod":{"conditions":[{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Data Platform Pod","type":"hasLabel","value":true},{"label":"Integrations Pod","type":"hasLabel","value":true}],"requires":1},"FE Coders Pod":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Debugger","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Error Handling","type":"hasLabel","value":true}],"requires":1},"App Viewers Pod":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"reallabel","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Branding","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Custom widgets","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true}],"requires":1},"UI Builders Pod":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Responsive Canvas","type":"hasLabel","value":true},{"label":"Responsive Widget","type":"hasLabel","value":true},{"label":"Responsive Viewport","type":"hasLabel","value":true},{"label":"Spacing","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"User Education Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true}],"requires":1},"Design System Pod":{"conditions":[{"label":"Design System Pod","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true}],"requires":1},"Data Platform Pod":{"conditions":[{"label":"Datasource Environments","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"Page load executions","type":"hasLabel","value":true},{"label":"DSL Update","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"DocumentDB","type":"hasLabel","value":true},{"label":"Multiple Environments","type":"hasLabel","value":true},{"label":"Platformization","type":"hasLabel","value":true},{"label":"Custom environments","type":"hasLabel","value":true},{"label":"Schema","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true}],"requires":1},"Integrations Pod":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"Onboarding","type":"hasLabel","value":true},{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"Welcome Screen","type":"hasLabel","value":true},{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Activation - learnability","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true}],"requires":1},"Git Pod":{"conditions":[{"label":"Git Version Control","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true},{"label":"Fork App","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true}],"requires":1},"Mobile Pod":{"conditions":[],"requires":1},"Billing & Usage Pod":{"conditions":[{"label":"CE Instance","type":"hasLabel","value":true},{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing Integrations","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"In-app ramps","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"Appsmith Business Cloud","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Embedding Apps","type":"hasLabel","value":true},{"label":"TM_BU","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"Invite users","type":"hasLabel","value":true},{"label":"Home Page","type":"hasLabel","value":true},{"label":"1-click upgrade","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Preview mode","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true}],"requires":1},"Appsmith Labs":{"conditions":[{"label":"AI","type":"hasLabel","value":true},{"label":"Knowledge Retrieval","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows","type":"hasLabel","value":true}],"requires":1},"Modules pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true}],"requires":1},"Templates Pod":{"conditions":[{"label":"Templates","type":"hasLabel","value":true},{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true}],"requires":1},"Widget design system POD":{"conditions":[{"label":"App Theming","type":"hasLabel","value":true},{"label":"Widget Styling","type":"hasLabel","value":true},{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Widget design system POD","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"9c0c8e","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"30c76d","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"Onboarding":{"color":"30c76d","name":"Onboarding","description":"Issues related to onboarding new developers"},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Widget Styling":{"color":"905420","name":"Widget Styling","description":"all about widget styling"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"App Viewers Pod":{"color":"cd8ef9","name":"App Viewers Pod","description":"This label assigns issues to the app viewers pod"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"30c76d","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Team Managers Pod":{"color":"bddb81","name":"Team Managers Pod","description":"Issues that team managers care about for the security and efficiency of their teams"},"Import-Export-App":{"color":"15076d","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"10b5ce","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"30c76d","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"IDE":{"color":"61b2ee","name":"IDE","description":"Issues related to the IDE"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Git Version Control":{"color":"858172","name":"Git Version Control","description":"Issues related to version control"},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"a2e2f9","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Debugger":{"color":"e79062","name":"Debugger","description":"Issues related to the debugger"},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"UI Builders Pod":{"color":"517fba","name":"UI Builders Pod","description":"Issues that UI Builders face using appsmith"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"In App Comms":{"name":"In App Comms","description":"Issues around communication with appsmith instances","color":"463cca"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"BE Coders Pod":{"color":"5d9848","name":"BE Coders Pod","description":"Issues related to users writing code to fetch and update data"},"FE Coders Pod":{"color":"a7effc","name":"FE Coders Pod","description":"Issues related to users writing javascript in appsmith"},"New Developers Pod":{"color":"6310da","name":"New Developers Pod","description":"Issues that new developers face while exploring the IDE"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"30c76d"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Responsive Viewport":{"color":"d12d2e","name":"Responsive Viewport","description":"Issues seen on different viewports like mobile"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"User Education Pod":{"name":"User Education Pod","description":"Issues related to user education","color":"1799b0"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Embedding Apps":{"name":"Embedding Apps","description":"Issues related to embedding","color":"30c76d"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"ef9c9d"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"50559d"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"30c76d"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"App Theming":{"name":"App Theming","description":"Items that are related to the App level theming controls epic","color":"905420"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":"bf019b"},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Templates":{"name":"Templates","description":"Issues related to templates","color":"b893f6"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"RBAC":{"name":"RBAC","description":"Issues, requests and enhancements around RBAC.","color":"9211c3"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Design System Pod":{"name":"Design System Pod","description":"Appsmith design system related issues","color":"706f03"},"ABAC":{"color":"e009a5","name":"ABAC","description":"User permissions and access controls"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"60885f"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"bc0cba"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"e4d966"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"418fa4"},"Branding":{"name":"Branding","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"7aaaf1"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"Audit Logs":{"name":"Audit Logs","description":"Audit trails to ensure data security","color":"f3fd62"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Data Platform Pod":{"name":"Data Platform Pod","description":"Issues related to the underlying data platform","color":"3f8c3a"},"Integrations Pod":{"name":"Integrations Pod","description":"Issues related to a specific integration","color":"5dbbb1"},"Datasource Environments":{"name":"Datasource Environments","description":"Issues related to datasource environments","color":"bb7a14"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"418fa4","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"6a5b42"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"c7da7a"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"e4d966"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"e4d966"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"e4d966"},"Page load executions":{"name":"Page load executions","description":"Issues related to page load execution","color":"5696b2"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Git Pod":{"name":"Git Pod","description":"Anything related to git sync","color":"2e5ba4"},"Mobile Pod":{"name":"Mobile Pod","description":"All issues related to mobile responsiveness","color":"6c97fd"},"Responsive Widget":{"name":"Responsive Widget","description":"All issues related to widget responsiveness","color":"d12d2e"},"Responsive Canvas":{"name":"Responsive Canvas","description":"All issues related to canvas responsiveness","color":"45a0a8"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Spacing":{"name":"Spacing","description":"All issue related to spacing between widgets in auto layout","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Error Handling":{"name":"Error Handling","description":"Issues related to error handling","color":"4e1872"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"434a3a"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"c476eb"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"Billing & Usage Pod":{"name":"Billing & Usage Pod","description":"Issues pertaining to licensing, billing, usage across self serve and enterprise customers","color":"256808"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"8154df"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"CE Instance":{"name":"CE Instance","description":"For all issues relating to usage, licensing or billing on the CE instance","color":"d2bc40"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"Billing Integrations":{"name":"Billing Integrations","description":"For all issues relating to 3P integrations Appsmith is using for billing & usage","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Appsmith Business Cloud":{"name":"Appsmith Business Cloud","description":"Issues related to our business cloud offering","color":"89bb6c"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"In-app ramps":{"name":"In-app ramps","description":"For all tasks/issues relating to adding in-app ramps in the community edition of the product","color":"8abae0"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"8d8a09"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"61a852"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"DocumentDB":{"name":"DocumentDB","description":"Issues related to support DocumentDB in Appsmith Data layer","color":"2c8b56"},"Multiple Environments":{"name":"Multiple Environments","description":"Issues or tasks related to multiple environments","color":"4e972b"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"75c4ce"},"Custom environments":{"name":"Custom environments","description":"Issues with creating or working with custom environments","color":"2137d6"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"144206"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Schema":{"name":"Schema","description":"Issues related to database schema","color":"c470c2"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"722bf0"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"IDE Pod":{"name":"IDE Pod","description":"https://app.zenhub.com/workspaces/new-developers-pod-60507ad1d4b98d00150a2858/board","color":"d3d248"},"TM_BU":{"name":"TM_BU","description":"The issues on Team Manager which needs to be taken up by Billing & Usage","color":"198cdf"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Appsmith Labs":{"name":"Appsmith Labs","description":"All things related to AI and other new initiatives ","color":"712d51"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":"23e6d6"},"Workflows Pod":{"name":"Workflows Pod","description":"For all issues related to the Workflows feature","color":"a86802"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"Knowledge Retrieval":{"name":"Knowledge Retrieval","description":"All issues related to knowledge retrieval on Appsmith AI","color":"a36890"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"1-click upgrade":{"name":"1-click upgrade","description":"For all issues/tasks related to 1-click upgrade & downgrade project","color":"51b5ff"},"Activation - learnability":{"name":"Activation - learnability","description":"Activation - learnability","color":"96fc76"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Modules pod":{"name":"Modules pod","description":"issues that belong to the modules pod","color":"4c6329"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package":{"name":"Package","description":"Issues related to packages","color":"2ad485"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Templates Pod":{"name":"Templates Pod","description":"Issues related to Templates","color":"e7b3b9"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"cce8e7"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"3fb8f2"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":""},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"4c1858"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Admin Settings":{"color":"32a316","name":"Admin Settings","description":"Issues related to admin settings"},"Workspace settings":{"name":"Workspace settings","description":"Issues related to workspace settings","color":"47d1ad"},"Page Management":{"color":"e17a68","name":"Page Management","description":"Issues related to configuring pages"},"Test":{"name":"Test","description":"","color":"33515b"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Workflows":{"name":"Workflows","description":"","color":"1b89db"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"8e3c7a"},"Widget design system POD":{"name":"Widget design system POD","description":"","color":"bbeecd"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"}},"success":true} \ No newline at end of file From d2c64344f9947b7c56b06573b073c80985419e40 Mon Sep 17 00:00:00 2001 From: Ayush Pahwa Date: Tue, 12 Mar 2024 14:00:42 +0530 Subject: [PATCH 02/25] chore: workflow ds icon update and beta card updates (#31681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Bumped version for for ds packages - Added `isBeta` flag to action operations to add BetaCard for EE repo Fixes #31357 ## Automation /ok-to-test tags="@tag.Sanity @tag.IDE" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `8cdee76bccace3a148077e983793475b75751592` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **New Features** - Enhanced the query list to include descriptions for beta features, improving user guidance and understanding of new functionalities. --- app/client/package.json | 4 ++-- .../Editor/IDE/EditorPane/Query/hooks.ts | 2 +- .../editorComponents/GlobalSearch/utils.tsx | 1 + app/client/yarn.lock | 20 +++++++++---------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/client/package.json b/app/client/package.json index 4f9717681d..b9ff538613 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -110,8 +110,8 @@ "d3-geo": "^3.1.0", "dayjs": "^1.10.6", "deep-diff": "^1.0.2", - "design-system": "npm:@appsmithorg/design-system@2.1.35", - "design-system-old": "npm:@appsmithorg/design-system-old@1.1.15", + "design-system": "npm:@appsmithorg/design-system@2.1.36", + "design-system-old": "npm:@appsmithorg/design-system-old@1.1.16", "downloadjs": "^1.4.7", "echarts": "^5.4.2", "fast-deep-equal": "^3.1.3", diff --git a/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts b/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts index 40e8f50f4f..6cea0964af 100644 --- a/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts +++ b/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts @@ -214,7 +214,7 @@ export const useAddQueryListItems = () => { fileOperation.entityExplorerTitle || fileOperation.dsName || fileOperation.title, - description: "", + description: !!fileOperation.isBeta ? "Beta" : "", descriptionType: "inline", onClick: onCreateItemClick.bind(null, fileOperation), } as ListItemProps; diff --git a/app/client/src/components/editorComponents/GlobalSearch/utils.tsx b/app/client/src/components/editorComponents/GlobalSearch/utils.tsx index c30156ba38..d012c47e8b 100644 --- a/app/client/src/components/editorComponents/GlobalSearch/utils.tsx +++ b/app/client/src/components/editorComponents/GlobalSearch/utils.tsx @@ -269,6 +269,7 @@ export interface ActionOperation { focusEntityType?: FocusEntity; dsName?: string; entityExplorerTitle?: string; + isBeta?: boolean; } export const actionOperations: ActionOperation[] = [ diff --git a/app/client/yarn.lock b/app/client/yarn.lock index 7e7df06642..c455af185e 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -13220,8 +13220,8 @@ __metadata: d3-geo: ^3.1.0 dayjs: ^1.10.6 deep-diff: ^1.0.2 - design-system: "npm:@appsmithorg/design-system@2.1.35" - design-system-old: "npm:@appsmithorg/design-system-old@1.1.15" + design-system: "npm:@appsmithorg/design-system@2.1.36" + design-system-old: "npm:@appsmithorg/design-system-old@1.1.16" diff: ^5.0.0 dotenv: ^8.1.0 downloadjs: ^1.4.7 @@ -17210,9 +17210,9 @@ __metadata: languageName: node linkType: hard -"design-system-old@npm:@appsmithorg/design-system-old@1.1.15": - version: 1.1.15 - resolution: "@appsmithorg/design-system-old@npm:1.1.15" +"design-system-old@npm:@appsmithorg/design-system-old@1.1.16": + version: 1.1.16 + resolution: "@appsmithorg/design-system-old@npm:1.1.16" dependencies: emoji-mart: 3.0.1 peerDependencies: @@ -17232,13 +17232,13 @@ __metadata: remixicon-react: ^1.0.0 styled-components: 5.3.6 tinycolor2: ^1.4.2 - checksum: 86cbe4523431e0cbe56ad5fcf9e8125ddb55b913442a418c717e30d1340332fc612549f6d458f5f523e8fa9ee96bb7bc3fc5c312255662701d09262766c23832 + checksum: 8fbfba86e54bdcbbb30b8e8b1902408ba0cb13f4d33d36c794f3bc0e281d0e2db8f716c10c6e0a3118f010db24f97c72606885bff4c320f41f5df9564ab6b214 languageName: node linkType: hard -"design-system@npm:@appsmithorg/design-system@2.1.35": - version: 2.1.35 - resolution: "@appsmithorg/design-system@npm:2.1.35" +"design-system@npm:@appsmithorg/design-system@2.1.36": + version: 2.1.36 + resolution: "@appsmithorg/design-system@npm:2.1.36" dependencies: "@radix-ui/react-dialog": ^1.0.2 "@radix-ui/react-dropdown-menu": ^2.0.4 @@ -17268,7 +17268,7 @@ __metadata: react-dom: ^17.0.2 react-router-dom: ^5.0.0 styled-components: ^5.3.6 - checksum: 06937082709a82d1f994977735999a5601427fae3423fe70bca6f5d7e0aaf487c4e3ade43348d91fd8285b2427046393444b9c097a38904e1d4532d8c6b37632 + checksum: 410db12c576560c6195d5b9ed776f1172c00985966b39d75fbfff119694f2227c94521e5e6d1c3068dd2d49fbac37975c2bc05b1284a09ef434ac7bd551bf84c languageName: node linkType: hard From 90760da7cababc05d92bf2f743466619012af124 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Tue, 12 Mar 2024 14:02:58 +0530 Subject: [PATCH 03/25] feat: New IDE Top Navbar (#31594) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Replaces the current App IDE Navbar with the new one. Fixes #31603 ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `5dba98f326ce504de0bf32b56c195d615279bf69` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **Refactor** - Centralized page management actions in Cypress tests using the new `PageList` module. - **Tests** - Enhanced Cypress test reliability and readability by consistently using `PageList` methods for page management. - **Chores** - Optimized test support infrastructure by removing outdated commands and imports in Cypress support files. --- .../Input_NavigateTo_validation_spec.js | 3 +- ...bleV2Widgets_NavigateTo_Validation_spec.js | 3 +- .../ExplorerTests/Hide_Page_spec.js | 5 +- .../ExplorerTests/Page_Load_Spec.js | 3 +- .../GitDiscardChange/DiscardChanges_spec.js | 4 +- .../ClientSide/Git/GitSync/GitBugs_spec.js | 8 +- .../Git/GitSync/GitSyncedApps_spec.js | 9 +- .../Git/GitSync/MergeViaRemote_spec.ts | 7 +- .../Git/GitSync/SwitchBranches_spec.js | 3 +- .../OtherUIFeatures/DynamicLayout_spec.js | 4 +- .../Iframe/Iframe_onSrcDocChange_spec.js | 8 +- .../ServerSide/GenerateCRUD/Mongo_Spec.ts | 3 +- .../ServerSide/GenerateCRUD/MySQL1_Spec.ts | 6 +- .../ServerSide/GenerateCRUD/Postgres1_Spec.ts | 5 +- .../ServerSide/GenerateCRUD/S3_Spec.js | 16 +--- .../ServerSide/QueryPane/Mongo1_spec.ts | 3 +- .../Sanity/Datasources/MsSQL_Basic_Spec.ts | 3 +- app/client/cypress/locators/Pages.json | 1 - .../cypress/locators/explorerlocators.json | 1 - .../cypress/support/Pages/EditorNavigation.ts | 3 +- .../cypress/support/Pages/EntityExplorer.ts | 2 + app/client/cypress/support/Pages/PageList.ts | 29 ++++++ app/client/cypress/support/commands.js | 26 ------ app/client/cypress/support/widgetCommands.js | 24 ++--- .../Editor/IDE/EditorPane/Query/hooks.ts | 1 - app/client/src/ce/pages/common/AppHeader.tsx | 17 +--- .../Editor/IDE/EditorPane/PagesSection.tsx | 1 + .../IDE/EditorPane/components/Pages.tsx | 17 ---- .../src/pages/Editor/IDE/EditorPane/index.tsx | 4 +- .../pages/Editor/IDE/Header/EditorTitle.tsx | 1 + .../src/pages/Editor/IDE/Header/index.tsx | 89 +++++++++---------- .../pages/Editor/IDE/LeftPane/PaneHeader.tsx | 3 +- 32 files changed, 132 insertions(+), 180 deletions(-) delete mode 100644 app/client/src/pages/Editor/IDE/EditorPane/components/Pages.tsx diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/Input_NavigateTo_validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/Input_NavigateTo_validation_spec.js index f66a1addb4..d9dc2b6aaf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/Input_NavigateTo_validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/Input_NavigateTo_validation_spec.js @@ -11,6 +11,7 @@ const publish = require("../../../../locators/publishWidgetspage.json"); const testdata = require("../../../../fixtures/testdata.json"); const pageid = "MyPage"; import { agHelper, propPane } from "../../../../support/Objects/ObjectsCore"; +import PageList from "../../../../support/Pages/PageList"; describe( "Binding the multiple Widgets and validating NavigateTo Page", @@ -33,7 +34,7 @@ describe( agHelper.AddDsl("displayWidgetDsl"); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(3000); - cy.CheckAndUnfoldEntityItem("Pages"); + PageList.ShowList(); PageLeftPane.assertPresence(pageid); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widgets_NavigateTo_Validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widgets_NavigateTo_Validation_spec.js index 06f9acb0ba..3e1fd59a7e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widgets_NavigateTo_Validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widgets_NavigateTo_Validation_spec.js @@ -12,6 +12,7 @@ import { propPane, deployMode, } from "../../../../support/Objects/ObjectsCore"; +import PageList from "../../../../support/Pages/PageList"; describe( "Table Widget V2 and Navigate to functionality validation", @@ -34,7 +35,7 @@ describe( agHelper.AddDsl("displayWidgetDsl"); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(500); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertPresence(pageid); //Table Widget V2 Functionality with multiple page EditorNavigation.SelectEntityByName("Page1", EntityType.Page); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Hide_Page_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Hide_Page_spec.js index a3ae877c73..1b44f3d403 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Hide_Page_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Hide_Page_spec.js @@ -4,14 +4,15 @@ import EditorNavigation, { } from "../../../../support/Pages/EditorNavigation"; import * as _ from "../../../../support/Objects/ObjectsCore"; +import PageList from "../../../../support/Pages/PageList"; describe( "Hide / Show page test functionality", { tags: ["@tag.IDE"] }, function () { it("1. Hide/Show page test ", function () { - cy.CreatePage(); // Page2 - cy.CreatePage(); // Page3 + PageList.AddNewPage(); // Page2 + PageList.AddNewPage(); // Page3 EditorNavigation.SelectEntityByName("Page1", EntityType.Page); _.entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Page2", diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Page_Load_Spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Page_Load_Spec.js index 2dfc825e2e..20a2a94ac4 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Page_Load_Spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Page_Load_Spec.js @@ -8,6 +8,7 @@ import { deployMode, entityExplorer, } from "../../../../support/Objects/ObjectsCore"; +import PageList from "../../../../support/Pages/PageList"; describe("Page Load tests", { tags: ["@tag.IDE"] }, () => { afterEach(() => { @@ -20,7 +21,7 @@ describe("Page Load tests", { tags: ["@tag.IDE"] }, () => { before(() => { agHelper.AddDsl("PageLoadDsl"); - cy.CreatePage(); + PageList.AddNewPage(); cy.get("h2").contains("Drag and drop a widget here"); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js index cfe385209d..bbeeb4f187 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js @@ -95,7 +95,7 @@ describe("Git discard changes:", { tags: ["@tag.Git"] }, function () { }); it("4. Delete page2 and trigger discard flow, page2 should be available again", () => { - cy.Deletepage(page2); + PageList.DeletePage(page2); // verify page is deleted //entityExplorer.ExpandCollapseEntity("Pages"); PageLeftPane.assertAbsence(page2); @@ -161,7 +161,7 @@ describe("Git discard changes:", { tags: ["@tag.Git"] }, function () { // discard changes gitSync.DiscardChanges(); // verify page3 is removed - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertAbsence(page3); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBugs_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBugs_spec.js index c196f5065a..637c496acc 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBugs_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBugs_spec.js @@ -15,6 +15,7 @@ import EditorNavigation, { PageLeftPane, PagePaneSegment, } from "../../../../../support/Pages/EditorNavigation"; +import PageList from "../../../../../support/Pages/PageList"; const pagename = "ChildPage"; const tempBranch = "feat/tempBranch"; @@ -48,11 +49,10 @@ describe("Git sync Bug #10773", { tags: ["@tag.Git"] }, function () { cy.wait(2000); gitSync.CreateGitBranch(tempBranch, false); //cy.createGitBranch(tempBranch); - cy.CheckAndUnfoldEntityItem("Pages"); // verify tempBranch should contain this page EditorNavigation.SelectEntityByName(pagename, EntityType.Page); // delete page from tempBranch and merge to master - cy.Deletepage(pagename); + PageList.DeletePage(pagename); cy.get(homePageLocators.publishButton).click(); cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); cy.get(gitSyncLocators.commitButton).click(); @@ -62,12 +62,12 @@ describe("Git sync Bug #10773", { tags: ["@tag.Git"] }, function () { cy.get(gitSyncLocators.closeGitSyncModal).click(); // verify ChildPage is not on master cy.switchGitBranch(mainBranch); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertAbsence(pagename); // create another branch and verify deleted page doesn't exist on it //cy.createGitBranch(tempBranch0); gitSync.CreateGitBranch(tempBranch0, false); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertAbsence(pagename); gitSync.DeleteTestGithubRepo(repoName); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js index a52efcabdf..804f24f784 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js @@ -277,7 +277,6 @@ describe("Git sync apps", { tags: ["@tag.Git"] }, function () { ); dataSources.RunQuery(); // create a new page - cy.CheckAndUnfoldEntityItem("Pages"); cy.Createpage("Child_Page"); EditorNavigation.SelectEntityByName(`${newPage} Copy`, EntityType.Page); EditorNavigation.SelectEntityByName("get_users", EntityType.Query); @@ -459,7 +458,7 @@ describe("Git sync apps", { tags: ["@tag.Git"] }, function () { // delete page from page settings EditorNavigation.SelectEntityByName("Child_Page Copy", EntityType.Page); cy.wait("@getConsolidatedData"); - cy.Deletepage("Child_Page Copy"); + PageList.DeletePage("Child_Page Copy"); cy.get(homePageLocators.publishButton).click(); cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); cy.get(gitSyncLocators.commitButton).click(); @@ -482,11 +481,11 @@ describe("Git sync apps", { tags: ["@tag.Git"] }, function () { expect(cellData).to.be.equal("New Config"); }); agHelper.AssertAutoSave(); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertAbsence("Child_Page Copy"); // create another branch and verify deleted page doesn't exist on it gitSync.CreateGitBranch(tempBranch0, true); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertAbsence("Child_Page Copy"); }); @@ -498,7 +497,7 @@ describe("Git sync apps", { tags: ["@tag.Git"] }, function () { // import application from git cy.importAppFromGit(repoName); // verify page order remains same as in orignal app - cy.CheckAndUnfoldEntityItem("Pages"); + PageList.ShowList(); cy.get(".t--entity-item").eq(1).contains("crudpage_1"); cy.get(".t--entity-item").eq(2).contains("crudpage_1 Copy"); cy.get(".t--entity-item").eq(3).contains("ApiCalls_1"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts index 1a5a748d6d..4f7e10a9d0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts @@ -1,12 +1,10 @@ -import widgetsPage from "../../../../../locators/Widgets.json"; -import commonlocators from "../../../../../locators/commonlocators.json"; import gitSyncLocators from "../../../../../locators/gitSyncLocators"; -import homePage from "../../../../../locators/HomePage"; import * as _ from "../../../../../support/Objects/ObjectsCore"; import { PageLeftPane, PagePaneSegment, } from "../../../../../support/Pages/EditorNavigation"; +import PageList from "../../../../../support/Pages/PageList"; let tempBranch = "tempBranch", tempBranch0 = "tempBranch0", @@ -57,7 +55,6 @@ describe( //cy.switchGitBranch(mainBranch); _.gitSync.CreateGitBranch(tempBranch2, true); PageLeftPane.switchSegment(PagePaneSegment.UI); - cy.CheckAndUnfoldEntityItem("Pages"); cy.Createpage("NewPage"); cy.commitAndPush(); cy.merge(mainBranch); @@ -79,7 +76,7 @@ describe( }); it("3. Checks clean url updates across branches", () => { - cy.Deletepage("NewPage"); + PageList.DeletePage("NewPage"); cy.wait(1000); let legacyPathname = ""; let newPathname = ""; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js index 24a2b8d88b..ef1ca01853 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js @@ -121,7 +121,7 @@ describe("Git sync:", { tags: ["@tag.Git"] }, function () { cy.switchGitBranch(parentBranchKey); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.assertAbsence("ParentPageRenamed"); PageLeftPane.switchSegment(PagePaneSegment.Queries); PageLeftPane.assertAbsence("ParentApiRenamed"); @@ -212,7 +212,6 @@ describe("Git sync:", { tags: ["@tag.Git"] }, function () { cy.generateUUID().then((uuid) => { gitSync.CreateGitBranch(childBranchKey, true); //cy.createGitBranch(childBranchKey); - cy.CheckAndUnfoldEntityItem("Pages"); PageList.AddNewPage(); cy.get(gitSyncLocators.branchButton).click({ force: true }); cy.get(gitSyncLocators.branchSearchInput).type("{selectall}master"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/DynamicLayout_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/DynamicLayout_spec.js index 7b3fc5763c..6722ab8527 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/DynamicLayout_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/DynamicLayout_spec.js @@ -1,5 +1,5 @@ const commonlocators = require("../../../../locators/commonlocators.json"); -const pages = require("../../../../locators/Pages.json"); +import PageList from "../../../../support/Pages/PageList"; describe("Dynamic Layout Functionality", function () { it("1. Dynamic Layout - Change Layout", function () { @@ -7,7 +7,7 @@ describe("Dynamic Layout Functionality", function () { cy.get(commonlocators.canvas).invoke("width").should("be.eq", 450); //Dynamic Layout - New Page should have selected Layout - cy.get(pages.AddPage).first().click(); + PageList.AddNewPage(); cy.get(commonlocators.canvas).invoke("width").should("be.eq", 450); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/Iframe_onSrcDocChange_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/Iframe_onSrcDocChange_spec.js index f788df7587..79a84b9f6a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/Iframe_onSrcDocChange_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/Iframe_onSrcDocChange_spec.js @@ -1,3 +1,4 @@ +import PageList from "../../../../../support/Pages/PageList"; const { ObjectsRegistry } = require("../../../../../support/Objects/Registry"); import EditorNavigation, { EntityType, @@ -31,13 +32,14 @@ describe( it("2.Check the OnSrcDocChange event call on first render", () => { agHelper.RefreshPage(); cy.wait(2000); - cy.get(`.t--entity .page`).first().should("have.class", "activePage"); + PageList.ShowList(); + PageList.VerifyIsCurrentPage("Page1"); cy.openPropertyPane("iframewidget"); cy.testJsontext("srcdoc", "

Hello World!

"); cy.wait(2000); - cy.get(`.t--entity .page`).last().should("have.class", "activePage"); + PageList.VerifyIsCurrentPage("Page2"); EditorNavigation.SelectEntityByName(page1, EntityType.Page); - cy.get(`.t--entity .page`).first().should("have.class", "activePage"); + PageList.VerifyIsCurrentPage("Page1"); }); }, ); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts index 732d801b9c..dfa1c2c48f 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts @@ -13,7 +13,6 @@ import { table, } from "../../../../support/Objects/ObjectsCore"; import PageList from "../../../../support/Pages/PageList"; -import { PageLeftPane } from "../../../../support/Pages/EditorNavigation"; describe( "Validate Mongo CRUD with JSON Form", @@ -78,7 +77,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(1, 0, "v2"); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "CoffeeCafe", action: "Delete", diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts index c912e524d2..d0ee3d3d60 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts @@ -14,9 +14,7 @@ import EditorNavigation, { AppSidebar, AppSidebarButton, EntityType, - PageLeftPane, } from "../../../../support/Pages/EditorNavigation"; -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import PageList from "../../../../support/Pages/PageList"; let dsName: any; @@ -55,7 +53,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Page2", action: "Delete", @@ -123,7 +121,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Employees", action: "Delete", diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts index 5f6b393ee5..70e6147c56 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts @@ -15,7 +15,6 @@ import EditorNavigation, { AppSidebar, AppSidebarButton, EntityType, - PageLeftPane, } from "../../../../support/Pages/EditorNavigation"; import PageList from "../../../../support/Pages/PageList"; @@ -50,7 +49,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Page2", action: "Delete", @@ -116,7 +115,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Public.orders", action: "Delete", diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/S3_Spec.js b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/S3_Spec.js index 9cf6db1030..7023f81a57 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/S3_Spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/S3_Spec.js @@ -142,20 +142,10 @@ describe( // }); //Create Dummy Page2 : - cy.CreatePage(); - cy.wait("@createPage").should( - "have.nested.property", - "response.body.responseMeta.status", - 201, - ); + PageList.AddNewPage(); //Creating CRUD Page3 - cy.CreatePage(); - cy.wait("@createPage").should( - "have.nested.property", - "response.body.responseMeta.status", - 201, - ); + PageList.AddNewPage(); cy.get("@dSName").then((dbName) => { PageList.AddNewPage("Generate page with data"); @@ -227,7 +217,7 @@ describe( }); it("4. Generate CRUD page from the page menu", function () { - cy.GenerateCRUD(); + PageList.AddNewPage("Generate page with data"); cy.NavigateToDSGeneratePage(datasourceName); // fetch bucket cy.wait("@getDatasourceStructure").should( diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts index 8813d0edd1..0fb427656f 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts @@ -14,7 +14,6 @@ import { } from "../../../../support/Objects/ObjectsCore"; import EditorNavigation, { EntityType, - PageLeftPane, } from "../../../../support/Pages/EditorNavigation"; import PageList from "../../../../support/Pages/PageList"; @@ -728,7 +727,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "AuthorNAwards", action: "Delete", diff --git a/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts b/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts index 2d9b228450..18fba758aa 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts @@ -16,7 +16,6 @@ import oneClickBindingLocator from "../../../locators/OneClickBindingLocator"; import { OneClickBinding } from "../../Regression/ClientSide/OneClickBinding/spec_utility"; import EditorNavigation, { EntityType, - PageLeftPane, } from "../../../support/Pages/EditorNavigation"; import PageList from "../../../support/Pages/PageList"; @@ -308,7 +307,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(); //Delete the test data - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Page2", action: "Delete", diff --git a/app/client/cypress/locators/Pages.json b/app/client/cypress/locators/Pages.json index 7952319436..850fb3571f 100644 --- a/app/client/cypress/locators/Pages.json +++ b/app/client/cypress/locators/Pages.json @@ -3,7 +3,6 @@ "formWidgets": ".t--page-sidebar-FormWidgets", "viewWidgets": ".t--page-sidebar-ViewWidgets", "widgetsEditor": ".t--nav-link-widgets-editor", - "AddPage": ".pages .t--entity-add-btn", "Menuaction": ".bp3-overlay-open>.bp3-transition-container", "Delete": ":nth-child(2) > .bp3-menu-item", "apiEditorIcon": ".t--nav-link-api-editor", diff --git a/app/client/cypress/locators/explorerlocators.json b/app/client/cypress/locators/explorerlocators.json index 8911f6abcc..282d66ad33 100644 --- a/app/client/cypress/locators/explorerlocators.json +++ b/app/client/cypress/locators/explorerlocators.json @@ -2,7 +2,6 @@ "NoApiMsg": "p:contains('No APIs yet.')", "NoQueryMsg": "p:contains('No DB Queries yet.')", "NoWidgetsMsg": "p:contains('icon above to add widgets')", - "AddPage": ".pages .t--entity-add-btn", "createQueryMenu": ".file-ops", "entityExplorer": ".t--entity-explorer", "popover": "//div[contains(@class,'t--entity page')]//*[local-name()='g' and @id='Icon/Outline/more-vertical']", diff --git a/app/client/cypress/support/Pages/EditorNavigation.ts b/app/client/cypress/support/Pages/EditorNavigation.ts index 273d9d3bf0..b016731c4c 100644 --- a/app/client/cypress/support/Pages/EditorNavigation.ts +++ b/app/client/cypress/support/Pages/EditorNavigation.ts @@ -3,6 +3,7 @@ import { ObjectsRegistry as _ } from "../Objects/Registry"; import ClickOptions = Cypress.ClickOptions; import { Sidebar } from "./IDE/Sidebar"; import { LeftPane } from "./IDE/LeftPane"; +import PageList from "./PageList"; export enum AppSidebarButton { Data = "Data", @@ -79,7 +80,7 @@ class EditorNavigation { NavigateToPage(name: string, networkCallAlias = false) { AppSidebar.navigate(AppSidebarButton.Editor); - PageLeftPane.expandCollapseItem("Pages"); + PageList.ShowList(); PageLeftPane.selectItem(name, { multiple: true, force: true }); _.AggregateHelper.Sleep(); //for selection to settle networkCallAlias && _.AssertHelper.AssertNetworkStatus("pageSnap"); diff --git a/app/client/cypress/support/Pages/EntityExplorer.ts b/app/client/cypress/support/Pages/EntityExplorer.ts index 34775b923b..b96c9dd114 100644 --- a/app/client/cypress/support/Pages/EntityExplorer.ts +++ b/app/client/cypress/support/Pages/EntityExplorer.ts @@ -7,6 +7,7 @@ import EditorNavigation, { PageLeftPane, PagePaneSegment, } from "./EditorNavigation"; +import PageList from "./PageList"; type templateActions = | "Find" @@ -255,6 +256,7 @@ export class EntityExplorer { viaMenu = false, ) { AppSidebar.navigate(AppSidebarButton.Editor); + PageList.ShowList(); if (viaMenu) this.ActionContextMenuByEntityName({ entityNameinLeftSidebar: entityName, diff --git a/app/client/cypress/support/Pages/PageList.ts b/app/client/cypress/support/Pages/PageList.ts index 5bfc87f47e..ca89ff269f 100644 --- a/app/client/cypress/support/Pages/PageList.ts +++ b/app/client/cypress/support/Pages/PageList.ts @@ -11,6 +11,7 @@ class PageList { `.t--entity.page:contains('${pageName}')`, newButton: ".pages .t--entity-add-btn", newPageOption: (option: string) => `//span[text()='${option}']/parent::div`, + switcher: `.t--pages-switcher`, }; public AddNewPage( @@ -20,12 +21,14 @@ class PageList { | "Add page from template" = "New blank page", ) { AppSidebar.navigate(AppSidebarButton.Editor); + this.ShowList(); ObjectsRegistry.AggregateHelper.GetNClick(this.locators.newButton); ObjectsRegistry.AggregateHelper.GetNClick( this.locators.newPageOption(option), ); if (option === "New blank page") { ObjectsRegistry.AssertHelper.AssertNetworkStatus("@createPage", 201); + return cy .get("@createPage") .then(($pageName: any) => $pageName.response?.body.data.name); @@ -33,6 +36,7 @@ class PageList { } public VerifyIsCurrentPage(pageName: string) { + this.ShowList(); ObjectsRegistry.AggregateHelper.GetElement( this.locators.pageListItem(pageName), ).should("have.class", "activePage"); @@ -44,6 +48,7 @@ class PageList { public ClonePage(pageName = "Page1") { AppSidebar.navigate(AppSidebarButton.Editor); + this.ShowList(); EditorNavigation.SelectEntityByName(pageName, EntityType.Page); ObjectsRegistry.EntityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: pageName, @@ -52,17 +57,41 @@ class PageList { ObjectsRegistry.AssertHelper.AssertNetworkStatus("@clonePage", 201); } + public ShowList() { + cy.get(this.locators.switcher).then(($switcher) => { + const isActive: string | undefined = $switcher.attr("data-active"); + if (isActive === "false") { + cy.get(this.locators.switcher).click(); + } + }); + } + assertPresence(pageName: string) { + this.ShowList(); ObjectsRegistry.AggregateHelper.AssertElementVisibility( this.locators.pageListItem(pageName), ); } assertAbsence(pageName: string) { + this.ShowList(); ObjectsRegistry.AggregateHelper.AssertElementAbsence( this.locators.pageListItem(pageName), ); } + + DeletePage(name: string) { + this.ShowList(); + cy.get(this.locators.pageListItem(name)).within(() => { + cy.get(".t--context-menu").click({ force: true }); + }); + cy.wait(2000); + cy.selectAction("Delete"); + cy.selectAction("Are you sure?"); + cy.wait("@deletePage") + .its("response.body.responseMeta.status") + .should("eq", 200); + } } export default new PageList(); diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js index 0cbfb2d98b..5e3297359b 100644 --- a/app/client/cypress/support/commands.js +++ b/app/client/cypress/support/commands.js @@ -5,7 +5,6 @@ import { ANVIL_EDITOR_TEST } from "./Constants.js"; import EditorNavigation, { EntityType, - AppSidebarButton, AppSidebar, PageLeftPane, PagePaneSegment, @@ -24,7 +23,6 @@ const loginPage = require("../locators/LoginPage.json"); const signupPage = require("../locators/SignupPage.json"); import homePage from "../locators/HomePage"; -const pages = require("../locators/Pages.json"); const commonlocators = require("../locators/commonlocators.json"); const widgetsPage = require("../locators/Widgets.json"); import ApiEditor from "../locators/ApiEditor"; @@ -390,14 +388,6 @@ Cypress.Commands.add("DeleteApp", (appName) => { cy.get(homePage.deleteApp).contains("Are you sure?").click({ force: true }); }); -Cypress.Commands.add("DeletepageFromSideBar", () => { - cy.xpath(pages.popover).last().click({ force: true }); - cy.get(pages.deletePage).first().click({ force: true }); - cy.get(pages.deletePageConfirm).first().click({ force: true }); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); -}); - Cypress.Commands.add("LogOut", (toCheckgetPluginForm = true) => { agHelper.WaitUntilAllToastsDisappear(); //Since these are coming in every self-hosted 1st time login, commenting for CI runs @@ -1952,22 +1942,6 @@ Cypress.Commands.add( }, ); -Cypress.Commands.add("CreatePage", () => { - AppSidebar.navigate(AppSidebarButton.Editor); - cy.get(pages.AddPage).first().click(); - cy.xpath("//span[text()='New blank page']/parent::div").click(); -}); - -Cypress.Commands.add("GenerateCRUD", () => { - cy.get(pages.AddPage).first().click(); - cy.xpath("//span[text()='Generate page with data']/parent::div").click(); -}); - -Cypress.Commands.add("AddPageFromTemplate", () => { - cy.get(pages.AddPage).first().click(); - cy.xpath("//span[text()='Add page from template']/parent::div").click(); -}); - Cypress.Commands.add(`verifyCallCount`, (alias, expectedNumberOfCalls) => { cy.wait(alias); cy.get(`${alias}.all`).should("have.length", expectedNumberOfCalls); diff --git a/app/client/cypress/support/widgetCommands.js b/app/client/cypress/support/widgetCommands.js index 48e5da8f26..113b931233 100644 --- a/app/client/cypress/support/widgetCommands.js +++ b/app/client/cypress/support/widgetCommands.js @@ -1,6 +1,8 @@ /* eslint-disable cypress/no-unnecessary-waiting */ /* eslint-disable cypress/no-assigning-return-values */ +import PageList from "./Pages/PageList"; + require("cy-verify-downloads").addCustomCommand(); require("cypress-file-upload"); const commonlocators = require("../locators/commonlocators.json"); @@ -929,31 +931,17 @@ Cypress.Commands.add("DeleteModal", () => { }); Cypress.Commands.add("Createpage", (pageName, navigateToCanvasPage = true) => { - cy.CreatePage(); - cy.wait("@createPage").then((xhr) => { - expect(xhr.response.body.responseMeta.status).to.equal(201); + PageList.AddNewPage().then((oldPageName) => { if (pageName) { - const pageId = xhr.response.body.data.id; - const oldPageName = xhr.response.body.data.name; cy.wait(2000); ee.RenameEntityFromExplorer(oldPageName, pageName, true); - cy.wrap(pageId).as("currentPageId"); } cy.get("#loading").should("not.exist"); }); -}); - -Cypress.Commands.add("Deletepage", (Pagename) => { - cy.CheckAndUnfoldEntityItem("Pages"); - cy.get(`.t--entity-item:contains(${Pagename})`).within(() => { - cy.get(".t--context-menu").click({ force: true }); + cy.get("@createPage").then((xhr) => { + const pageId = xhr.response.body.data.id; + cy.wrap(pageId).as("currentPageId"); }); - cy.wait(2000); - cy.selectAction("Delete"); - cy.selectAction("Are you sure?"); - cy.wait("@deletePage") - .its("response.body.responseMeta.status") - .should("eq", 200); }); Cypress.Commands.add("dropdownDynamic", (text) => { diff --git a/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts b/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts index 6cea0964af..f9ee3a481b 100644 --- a/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts +++ b/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.ts @@ -60,7 +60,6 @@ export const useQueryAdd = () => { return addButtonClickHandler; }; -//history.push(location.pathname.replace(`${ADD_PATH}`, "")); export type GroupedAddOperations = Array<{ title?: string; diff --git a/app/client/src/ce/pages/common/AppHeader.tsx b/app/client/src/ce/pages/common/AppHeader.tsx index 2821539d6e..7406aeeae5 100644 --- a/app/client/src/ce/pages/common/AppHeader.tsx +++ b/app/client/src/ce/pages/common/AppHeader.tsx @@ -18,22 +18,13 @@ import { } from "constants/routes"; import Navigation from "pages/AppViewer/Navigation"; import type { RouteComponentProps } from "react-router"; -import AppEditorHeader from "pages/Editor/EditorHeader"; -import { Header } from "pages/Editor/IDE/Header"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; -import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { Header as AppIDEHeader } from "pages/Editor/IDE/Header"; export type Props = RouteComponentProps; export const headerRoot = document.getElementById("header-root"); export const Routes = () => { - const isSideBySideFlagEnabled = useFeatureFlag( - FEATURE_FLAG.release_side_by_side_ide_enabled, - ); - - const HeaderComponent = isSideBySideFlagEnabled ? Header : AppEditorHeader; - return ( @@ -46,10 +37,10 @@ export const Routes = () => { exact path={CUSTOM_WIDGETS_EDITOR_ID_PATH_CUSTOM} /> - + - - + + diff --git a/app/client/src/pages/Editor/IDE/EditorPane/PagesSection.tsx b/app/client/src/pages/Editor/IDE/EditorPane/PagesSection.tsx index d6669f43a3..d13268dc9c 100644 --- a/app/client/src/pages/Editor/IDE/EditorPane/PagesSection.tsx +++ b/app/client/src/pages/Editor/IDE/EditorPane/PagesSection.tsx @@ -102,6 +102,7 @@ const PagesSection = () => { style={springs} > { - const isSideBySideEnabled = useSelector(getIsSideBySideEnabled); - - if (!isSideBySideEnabled) { - return ; - } else { - return ; - } -}; - -export { Pages }; diff --git a/app/client/src/pages/Editor/IDE/EditorPane/index.tsx b/app/client/src/pages/Editor/IDE/EditorPane/index.tsx index d2529b38b8..7003f66dcd 100644 --- a/app/client/src/pages/Editor/IDE/EditorPane/index.tsx +++ b/app/client/src/pages/Editor/IDE/EditorPane/index.tsx @@ -9,7 +9,7 @@ import EditorPaneSegments from "./EditorPaneSegments"; import GlobalAdd from "./GlobalAdd"; import { useEditorPaneWidth } from "../hooks"; import EntityProperties from "pages/Editor/Explorer/Entity/EntityProperties"; -import { Pages } from "./components/Pages"; +import { PagesSection } from "./PagesSection"; const EditorPane = ({ match: { path } }: RouteComponentProps) => { const width = useEditorPaneWidth(); @@ -26,7 +26,7 @@ const EditorPane = ({ match: { path } }: RouteComponentProps) => { {/** Entity Properties component is needed to render the Bindings popover in the context menu. Will be removed eventually **/} - + diff --git a/app/client/src/pages/Editor/IDE/Header/EditorTitle.tsx b/app/client/src/pages/Editor/IDE/Header/EditorTitle.tsx index fd0d162e03..1361474410 100644 --- a/app/client/src/pages/Editor/IDE/Header/EditorTitle.tsx +++ b/app/client/src/pages/Editor/IDE/Header/EditorTitle.tsx @@ -32,6 +32,7 @@ const EditorTitle = ({ title }: { title: string }) => { { const pageId = useSelector(getCurrentPageId) as string; const currentPage = useSelector(getPageById(pageId)); const appState = useCurrentAppState(); + const isSaving = useSelector(getIsPageSaving); + const pageSaveError = useSelector(getPageSavingError); // states const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -202,7 +206,6 @@ const Header = () => { className={"t--editor-header"} height={"40px"} overflow={"hidden"} - px={"spaces-4"} width={"100%"} > { gap={"spaces-4"} height={"100%"} justifyContent={"left"} + pl={"spaces-4"} > + { height={"100%"} justifyContent={"center"} > - - - {currentWorkspace.name && ( - <> - - {currentWorkspace.name + " / "} - - el.id === applicationId) - .length > 0 - } - isPopoverOpen={isPopoverOpen} - onBlur={(value: string) => - updateApplicationDispatch(applicationId || "", { - name: value, - currentApp: true, - }) - } - setIsPopoverOpen={setIsPopoverOpen} - /> - - )} - - + + {currentWorkspace.name && ( + <> + + {currentWorkspace.name + " / "} + + el.id === applicationId) + .length > 0 + } + isPopoverOpen={isPopoverOpen} + onBlur={(value: string) => + updateApplicationDispatch(applicationId || "", { + name: value, + currentApp: true, + }) + } + setIsPopoverOpen={setIsPopoverOpen} + /> + + )} + + {props.title} {props.rightIcon ? props.rightIcon : null} From 29cc9d39d5cc7c8c3fb1048ab1f37c21fe38f565 Mon Sep 17 00:00:00 2001 From: albinAppsmith <87797149+albinAppsmith@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:13:52 +0530 Subject: [PATCH 04/25] feat: Added split pane beta announcement modal (#31676) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR adds the beta announcement modal for the new split pane. Fixes #31657 ## Automation /ok-to-test tags="@tag.Sanity, @tag.IDE" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `8f20379a3f045328c0c7fa0ddce9b28d34a86348` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **New Features** - Introduced a beta version feature allowing users to work with code and UI side-by-side, enhancing productivity and user experience. - Added an announcement modal to inform users about the new split-screen functionality, with options to try it immediately or learn more. --- app/client/src/ce/constants/messages.ts | 5 ++ .../EditorPane/components/Announcement.tsx | 51 +++++++++++++++++++ .../Editor/IDE/EditorTabs/SplitScreenTabs.tsx | 30 ++++++----- app/client/src/utils/localStorage.tsx | 1 + 4 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 app/client/src/pages/Editor/IDE/EditorPane/components/Announcement.tsx diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 9bb3e1a5b4..3867df4500 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -2459,3 +2459,8 @@ export const CREATE_A_NEW_ITEM = (item: string) => `Create a new ${item}`; export const MAXIMIZE_BUTTON_TOOLTIP = () => `Expand code editor to full-screen`; export const MINIMIZE_BUTTON_TOOLTIP = () => `Open code editor next to the UI`; +export const SPLITPANE_ANNOUNCEMENT = { + TITLE: () => "Code and UI side-by-side", + DESCRIPTION: () => + "You can now write queries & JS functions as you refer to your UI on the side. This is a beta version that we will continue to improve with your feedback.", +}; diff --git a/app/client/src/pages/Editor/IDE/EditorPane/components/Announcement.tsx b/app/client/src/pages/Editor/IDE/EditorPane/components/Announcement.tsx new file mode 100644 index 0000000000..5873b9b22a --- /dev/null +++ b/app/client/src/pages/Editor/IDE/EditorPane/components/Announcement.tsx @@ -0,0 +1,51 @@ +import React, { useState } from "react"; +import { AnnouncementModal, Button } from "design-system"; +import localStorage, { LOCAL_STORAGE_KEYS } from "utils/localStorage"; +import { + SPLITPANE_ANNOUNCEMENT, + createMessage, +} from "@appsmith/constants/messages"; +import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; +import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants"; + +const Announcement = () => { + const localStorageFlag = + localStorage.getItem(LOCAL_STORAGE_KEYS.SPLITPANE_ANNOUNCEMENT) || "true"; + const [show, setShow] = useState(JSON.parse(localStorageFlag)); + + const tryClickHandler = () => { + setShow(false); + localStorage.setItem(LOCAL_STORAGE_KEYS.SPLITPANE_ANNOUNCEMENT, "false"); + }; + + const learnClickHandler = () => { + window.open( + "https://community.appsmith.com/content/blog/discover-ide-20-building-more-efficient-ide", + "_blank", + ); + }; + + const modalFooter = () => ( + <> + + + + ); + + return ( + + ); +}; + +export { Announcement }; diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx index 3f5559d846..eefaec4130 100644 --- a/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx +++ b/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx @@ -19,6 +19,7 @@ import { getCurrentPageId } from "@appsmith/selectors/entitiesSelector"; import history, { NavigationMethod } from "utils/history"; import { includes } from "lodash"; import ListButton from "./ListButton"; +import { Announcement } from "../EditorPane/components/Announcement"; const SplitScreenTabs = () => { const isSideBySideEnabled = useSelector(getIsSideBySideEnabled); @@ -53,18 +54,23 @@ const SplitScreenTabs = () => { if (!isSideBySideEnabled) return null; if (ideViewMode === EditorViewMode.FullScreen) return null; if (segment === EditorEntityTab.UI) return null; - return files.length > 0 ? ( - - - - - - ) : null; + return ( + <> + {files.length > 0 ? ( + + + + + + ) : null} + + + ); }; export default SplitScreenTabs; diff --git a/app/client/src/utils/localStorage.tsx b/app/client/src/utils/localStorage.tsx index e8fe777f39..9418e33071 100644 --- a/app/client/src/utils/localStorage.tsx +++ b/app/client/src/utils/localStorage.tsx @@ -9,6 +9,7 @@ import { toast } from "design-system"; export const LOCAL_STORAGE_KEYS = { CANVAS_CARDS_STATE: "CANVAS_CARDS_STATE", + SPLITPANE_ANNOUNCEMENT: "SPLITPANE_ANNOUNCEMENT", }; class LocalStorageNotSupportedError extends Error { From 127e96c3f1540646e52ac5d329e6d84013531616 Mon Sep 17 00:00:00 2001 From: Nilesh Sarupriya Date: Tue, 12 Mar 2024 05:05:28 -0500 Subject: [PATCH 05/25] chore: code split refactor of generateActionCollectionViewDTO and setAutoGeneratedHeaders (#31620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description > code split methods to support native triggering of workflows. #### PR fixes following issue(s) Fixes # (issue number) > if no issue exists, please create an issue and ask the maintainers about this first > > #### Media > A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video > > #### Type of change > Please delete options that are not relevant. - Bug fix (non-breaking change which fixes an issue) - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) - Chore (housekeeping or task changes that don't impact user perception) - This change requires a documentation update > > > ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] JUnit - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed ## Summary by CodeRabbit - **New Features** - Enhanced the action collection view with additional parameters for better access control and view mode handling. - Improved action execution process by enabling the setting of auto-generated headers dynamically, enhancing the flexibility and customization of action executions. Co-authored-by: Nilesh Sarupriya <20905988+nsarupr@users.noreply.github.com> --- .../base/ActionCollectionServiceCEImpl.java | 8 ++++++-- .../ce/ActionExecutionSolutionCEImpl.java | 14 +++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java index 7f6fbde919..9bbdb68bc4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java @@ -224,6 +224,11 @@ public class ActionCollectionServiceCEImpl extends BaseService generateActionCollectionViewDTO(ActionCollection actionCollection) { + return generateActionCollectionViewDTO(actionCollection, actionPermission.getExecutePermission(), true); + } + + protected Mono generateActionCollectionViewDTO( + ActionCollection actionCollection, AclPermission aclPermission, boolean viewMode) { if (actionCollection.getPublishedCollection() == null) { return Mono.empty(); } @@ -256,8 +261,7 @@ public class ActionCollectionServiceCEImpl extends BaseService newActionService.findActionDTObyIdAndViewMode( - actionId, true, actionPermission.getExecutePermission())) + .flatMap(actionId -> newActionService.findActionDTObyIdAndViewMode(actionId, viewMode, aclPermission)) .collectList() .map(actionDTOList -> { actionCollectionViewDTO.setActions(actionDTOList); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java index 069b1c13ba..450f1ac463 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java @@ -810,11 +810,13 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE Integer timeoutDuration = actionDTO.getActionConfiguration().getTimeoutInMillisecond(); - setAutoGeneratedHeaders(plugin, actionDTO, httpHeaders); + Mono actionDTOWithAutoGeneratedHeadersMono = + setAutoGeneratedHeaders(plugin, actionDTO, httpHeaders); - Mono actionExecutionResultMono = verifyDatasourceAndMakeRequest( - executeActionDTO, actionDTO, datasourceStorage, plugin, pluginExecutor) - .timeout(Duration.ofMillis(timeoutDuration)); + Mono actionExecutionResultMono = + actionDTOWithAutoGeneratedHeadersMono.flatMap(actionDTO1 -> verifyDatasourceAndMakeRequest( + executeActionDTO, actionDTO, datasourceStorage, plugin, pluginExecutor) + .timeout(Duration.ofMillis(timeoutDuration))); return actionExecutionResultMono .onErrorMap(executionExceptionMapper(actionDTO, timeoutDuration)) @@ -1136,5 +1138,7 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE }); } - protected void setAutoGeneratedHeaders(Plugin plugin, ActionDTO actionDTO, HttpHeaders httpHeaders) {} + protected Mono setAutoGeneratedHeaders(Plugin plugin, ActionDTO actionDTO, HttpHeaders httpHeaders) { + return Mono.just(actionDTO); + } } From c5ed198383e1d6ac073cc251f02981a382714f34 Mon Sep 17 00:00:00 2001 From: sneha122 Date: Tue, 12 Mar 2024 15:36:33 +0530 Subject: [PATCH 06/25] chore: execute action event updated with source (#31662) --- app/client/src/actions/pluginActionActions.ts | 19 ++++-- app/client/src/ce/sagas/PageSagas.tsx | 13 ++++- .../src/ce/utils/actionExecutionUtils.ts | 2 + app/client/src/entities/Action/index.ts | 12 ++++ .../sagas/ActionExecution/PluginActionSaga.ts | 58 ++++++++++++------- app/client/src/sagas/OneClickBindingSaga.ts | 11 +++- 6 files changed, 87 insertions(+), 28 deletions(-) diff --git a/app/client/src/actions/pluginActionActions.ts b/app/client/src/actions/pluginActionActions.ts index 65323ce66f..291dcc982d 100644 --- a/app/client/src/actions/pluginActionActions.ts +++ b/app/client/src/actions/pluginActionActions.ts @@ -3,7 +3,6 @@ import type { EvaluationReduxAction, AnyReduxAction, ReduxAction, - ReduxActionWithoutPayload, } from "@appsmith/constants/ReduxActionConstants"; import type { JSUpdate } from "utils/JSPaneUtils"; import { @@ -11,6 +10,7 @@ import { ReduxActionTypes, } from "@appsmith/constants/ReduxActionConstants"; import type { Action, ActionViewMode } from "entities/Action"; +import { ActionExecutionContext } from "entities/Action"; import { batchAction } from "actions/batchActions"; import type { ExecuteErrorPayload } from "constants/AppsmithActionConstants/ActionConstants"; import type { ModalInfo } from "reducers/uiReducers/modalActionReducer"; @@ -107,6 +107,8 @@ export const runAction = ( id: string, paginationField?: PaginationField, skipOpeningDebugger = false, + action = undefined, + actionExecutionContext = ActionExecutionContext.SELF, ) => { return { type: ReduxActionTypes.RUN_ACTION_REQUEST, @@ -114,6 +116,8 @@ export const runAction = ( id, paginationField, skipOpeningDebugger, + action, + actionExecutionContext, }, }; }; @@ -314,9 +318,16 @@ export const updateActionProperty = ( }); }; -export const executePageLoadActions = (): ReduxActionWithoutPayload => ({ - type: ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS, -}); +export const executePageLoadActions = ( + actionExecutionContext?: ActionExecutionContext, +) => { + return { + type: ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS, + payload: { + actionExecutionContext, + }, + }; +}; export const executeJSUpdates = ( payload: Record, diff --git a/app/client/src/ce/sagas/PageSagas.tsx b/app/client/src/ce/sagas/PageSagas.tsx index 4eeed87b5f..d4b6fa320c 100644 --- a/app/client/src/ce/sagas/PageSagas.tsx +++ b/app/client/src/ce/sagas/PageSagas.tsx @@ -145,6 +145,7 @@ import type { DSLWidget } from "WidgetProvider/constants"; import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; import { getIsServerDSLMigrationsEnabled } from "selectors/pageSelectors"; import { getCurrentWorkspaceId } from "@appsmith/selectors/selectedWorkspaceSelectors"; +import { ActionExecutionContext } from "entities/Action"; export const checkIfMigrationIsNeeded = ( fetchPageResponse?: FetchPageResponse, @@ -977,7 +978,11 @@ export function* clonePageSaga( } yield put(selectWidgetInitAction(SelectionRequestType.Empty)); - yield put(fetchAllPageEntityCompletion([executePageLoadActions()])); + yield put( + fetchAllPageEntityCompletion([ + executePageLoadActions(ActionExecutionContext.CLONE_PAGE), + ]), + ); // TODO: Update URL params here. @@ -1374,7 +1379,11 @@ export function* generateTemplatePageSaga( if (!afterActionsFetch) { throw new Error("Failed generating template"); } - yield put(fetchAllPageEntityCompletion([executePageLoadActions()])); + yield put( + fetchAllPageEntityCompletion([ + executePageLoadActions(ActionExecutionContext.GENERATE_CRUD_PAGE), + ]), + ); history.replace( builderURL({ diff --git a/app/client/src/ce/utils/actionExecutionUtils.ts b/app/client/src/ce/utils/actionExecutionUtils.ts index 66d492ee7b..c19892c55c 100644 --- a/app/client/src/ce/utils/actionExecutionUtils.ts +++ b/app/client/src/ce/utils/actionExecutionUtils.ts @@ -1,4 +1,5 @@ import type { Action } from "entities/Action"; +import { ActionExecutionContext } from "entities/Action"; import type { JSAction, JSCollection } from "entities/JSCollection"; import type { ApplicationPayload } from "@appsmith/constants/ReduxActionConstants"; import store from "store"; @@ -65,6 +66,7 @@ export function getActionExecutionAnalytics( isMock: !!datasource?.isMock, actionId: action?.id, inputParams: Object.keys(params).length, + source: ActionExecutionContext.EVALUATION_ACTION_TRIGGER, // Used in analytic events to understand who triggered action execution }; if (!!currentApp) { diff --git a/app/client/src/entities/Action/index.ts b/app/client/src/entities/Action/index.ts index 54b3066456..bea5f25a53 100644 --- a/app/client/src/entities/Action/index.ts +++ b/app/client/src/entities/Action/index.ts @@ -75,6 +75,18 @@ export enum ActionCreationSourceTypeEnum { COPY_ACTION = "COPY_ACTION", } +// Used for analytic events +export enum ActionExecutionContext { + SELF = "SELF", + ONE_CLICK_BINDING = "ONE_CLICK_BINDING", + GENERATE_CRUD_PAGE = "GENERATE_CRUD_PAGE", + CLONE_PAGE = "CLONE_PAGE", + FORK_TEMPLATE_PAGE = "FORK_TEMPLATE_PAGE", + PAGE_LOAD = "PAGE_LOAD", + EVALUATION_ACTION_TRIGGER = "EVALUATION_ACTION_TRIGGER", + REFRESH_ACTIONS_ON_ENV_CHANGE = "REFRESH_ACTIONS_ON_ENV_CHANGE", +} + export interface KeyValuePair { key?: string; value?: unknown; diff --git a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts index 83f4c7c43f..eb683cdce6 100644 --- a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts @@ -9,6 +9,7 @@ import { } from "redux-saga/effects"; import * as Sentry from "@sentry/react"; import type { updateActionDataPayloadType } from "actions/pluginActionActions"; +import { executePageLoadActions } from "actions/pluginActionActions"; import { clearActionResponse, executePluginActionError, @@ -77,6 +78,7 @@ import { import type { EventName } from "@appsmith/utils/analyticsUtilTypes"; import AnalyticsUtil from "utils/AnalyticsUtil"; import type { Action } from "entities/Action"; +import { ActionExecutionContext } from "entities/Action"; import { PluginType } from "entities/Action"; import LOG_TYPE from "entities/AppsmithConsole/logtype"; import { @@ -742,6 +744,7 @@ export function* runActionSaga( paginationField?: PaginationField; skipOpeningDebugger: boolean; action?: Action; + actionExecutionContext?: ActionExecutionContext; }>, ) { const span = startRootSpan("runActionSaga"); @@ -956,14 +959,7 @@ export function* runActionSaga( show: false, }, }); - let failureEventName: EventName = "RUN_API_FAILURE"; - if (actionObject.pluginType === PluginType.DB) { - failureEventName = "RUN_QUERY_FAILURE"; - } - if (actionObject.pluginType === PluginType.SAAS) { - failureEventName = "RUN_SAAS_API_FAILURE"; - } - AnalyticsUtil.logEvent(failureEventName, { + AnalyticsUtil.logEvent("EXECUTE_ACTION_FAILURE", { actionId, actionName: pluginActionNameToDisplay, environmentId: currentEnvDetails.id, @@ -975,19 +971,12 @@ export function* runActionSaga( isMock: !!datasource?.isMock, actionConfig: actionAnalyticsPayload, ...payload?.pluginErrorDetails, + source: reduxAction.payload.actionExecutionContext, }); return; } - let eventName: EventName = "RUN_API"; - if (actionObject.pluginType === PluginType.DB) { - eventName = "RUN_QUERY"; - } - if (actionObject.pluginType === PluginType.SAAS) { - eventName = "RUN_SAAS_API"; - } - - AnalyticsUtil.logEvent(eventName, { + AnalyticsUtil.logEvent("EXECUTE_ACTION", { actionId, actionName: pluginActionNameToDisplay, environmentId: currentEnvDetails.id, @@ -999,6 +988,7 @@ export function* runActionSaga( pluginName: plugin?.name, isMock: !!datasource?.isMock, actionConfig: actionAnalyticsPayload, + source: reduxAction.payload.actionExecutionContext, }); yield put({ @@ -1100,7 +1090,11 @@ function* executeOnPageLoadJSAction(pageAction: PageAction) { } } -function* executePageLoadAction(pageAction: PageAction, span?: OtlpSpan) { +function* executePageLoadAction( + pageAction: PageAction, + span?: OtlpSpan, + actionExecutionContext?: ActionExecutionContext, +) { const currentEnvDetails: { id: string; name: string } = yield select( getCurrentEnvironmentDetails, ); @@ -1137,6 +1131,9 @@ function* executePageLoadAction(pageAction: PageAction, span?: OtlpSpan) { isMock: !!datasource?.isMock, actionId: pageAction?.id, inputParams: 0, + source: !!actionExecutionContext + ? actionExecutionContext + : ActionExecutionContext.PAGE_LOAD, }); const actionName = getPluginActionNameToDisplay( @@ -1247,6 +1244,9 @@ function* executePageLoadAction(pageAction: PageAction, span?: OtlpSpan) { actionId: pageAction?.id, inputParams: 0, ...payload.pluginErrorDetails, + source: !!actionExecutionContext + ? actionExecutionContext + : ActionExecutionContext.PAGE_LOAD, }); } else { AnalyticsUtil.logEvent("EXECUTE_ACTION_SUCCESS", { @@ -1265,6 +1265,9 @@ function* executePageLoadAction(pageAction: PageAction, span?: OtlpSpan) { isMock: !!datasource?.isMock, actionId: pageAction?.id, inputParams: 0, + source: !!actionExecutionContext + ? actionExecutionContext + : ActionExecutionContext.PAGE_LOAD, }); PerformanceTracker.stopAsyncTracking( PerformanceTransactionName.EXECUTE_ACTION, @@ -1285,7 +1288,11 @@ function* executePageLoadAction(pageAction: PageAction, span?: OtlpSpan) { } } -function* executePageLoadActionsSaga() { +function* executePageLoadActionsSaga( + actionPayload: ReduxAction<{ + actionExecutionContext?: ActionExecutionContext; + }>, +) { const span = startRootSpan("executePageLoadActionsSaga"); try { const pageActions: PageAction[][] = yield select(getLayoutOnLoadActions); @@ -1305,7 +1312,12 @@ function* executePageLoadActionsSaga() { // @ts-expect-error: no idea how to type this yield* yield all( actionSet.map((apiAction) => - call(executePageLoadAction, apiAction, span), + call( + executePageLoadAction, + apiAction, + span, + actionPayload.payload.actionExecutionContext, + ), ), ); } @@ -1626,7 +1638,11 @@ function* softRefreshActionsSaga() { // Clear all the action responses on the page yield call(clearTriggerActionResponse); //Rerun all the page load actions on the page - yield call(executePageLoadActionsSaga); + yield put( + executePageLoadActions( + ActionExecutionContext.REFRESH_ACTIONS_ON_ENV_CHANGE, + ), + ); try { // we fork to prevent the call from blocking yield put(softRefreshDatasourceStructure()); diff --git a/app/client/src/sagas/OneClickBindingSaga.ts b/app/client/src/sagas/OneClickBindingSaga.ts index f6d644c279..da4006121c 100644 --- a/app/client/src/sagas/OneClickBindingSaga.ts +++ b/app/client/src/sagas/OneClickBindingSaga.ts @@ -6,6 +6,7 @@ import { import type { Plugin } from "api/PluginApi"; import { ActionCreationSourceTypeEnum, + ActionExecutionContext, PluginType, type Action, type QueryActionConfig, @@ -223,7 +224,15 @@ function* BindWidgetToDatasource( //TODO(Balaji): Need to make changes to plugin saga to execute the actions in parallel for (const actionToRun of actionsToRun) { - yield put(runAction(actionToRun.id, undefined, true)); + yield put( + runAction( + actionToRun.id, + undefined, + true, + undefined, + ActionExecutionContext.ONE_CLICK_BINDING, + ), + ); const runResponse: ReduxAction = yield take([ ReduxActionTypes.RUN_ACTION_SUCCESS, From 0af7c7ecbb5b07b1899619e207a69f98b2ccdab7 Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Tue, 12 Mar 2024 15:53:49 +0530 Subject: [PATCH 07/25] chore: Remove non-static `or` API in Bridge (#31678) Removing the `BridgeQuery.or` API since 1. it reads confusing. Are the passed-in items applied with an `or`, or the current queries applied with the parameters with an `or`. Unlike `and` method, this difference with `or` can change the meaning of the query drastically. 2. it doesn't translate very well into Postgres world. Multiple hoops to manage the same API, just not worth it. The static `Bridge.or` looks, reads, and works much better. That's the suggested alternative for this. --- .../server/helpers/ce/bridge/BridgeQuery.java | 13 ++++++++----- .../ce/CustomNewActionRepositoryCEImpl.java | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java index 182917e5bd..629b8ca03f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java @@ -88,13 +88,16 @@ public final class BridgeQuery extends Criteria { return this; } - public BridgeQuery or(BridgeQuery... items) { - checks.add(new Criteria().orOperator(items)); - return this; + /** + * Please use {@code Bridge.or} instead. This API looks and reads very confusing and unintuitive, so is explicitly + * disabled. + */ + public BridgeQuery or(BridgeQuery ignoredUnused) { + throw new UnsupportedOperationException("Not supported"); } - public BridgeQuery and(BridgeQuery... items) { - checks.add(new Criteria().andOperator(items)); + public BridgeQuery and(BridgeQuery item) { + checks.add(new Criteria().andOperator(item)); return this; } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java index 47f444cbff..d722a4e7c2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java @@ -167,9 +167,9 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl< BridgeQuery q = Bridge.equal(NewAction.Fields.unpublishedAction_pageId, pageId); if (names != null) { - q.or( + q.and(Bridge.or( Bridge.in(NewAction.Fields.unpublishedAction_name, names), - Bridge.in(NewAction.Fields.unpublishedAction_fullyQualifiedName, names)); + Bridge.in(NewAction.Fields.unpublishedAction_fullyQualifiedName, names))); } // In case an action has been deleted in edit mode, but still exists in deployed mode, NewAction object would From 3a8064ad5febcda5d78262a16e94f48ccef5e5ad Mon Sep 17 00:00:00 2001 From: ashit-rath Date: Tue, 12 Mar 2024 17:24:19 +0530 Subject: [PATCH 08/25] chore: reconnect modal refactor for package import (#31674) --- app/client/src/ce/actions/workspaceActions.ts | 4 + .../src/ce/constants/ReduxActionConstants.tsx | 1 + .../Editor/gitSync/useReconnectModalData.ts | 33 ++++++++ .../uiReducers/applicationsReducer.tsx | 6 ++ .../Editor/gitSync/useReconnectModalData.ts | 3 + ...uccessModal.tsx => ImportSuccessModal.tsx} | 23 ++++-- .../gitSync/ReconnectDatasourceModal.tsx | 80 ++++++++++--------- app/client/src/pages/Editor/index.tsx | 2 +- 8 files changed, 106 insertions(+), 46 deletions(-) create mode 100644 app/client/src/ce/pages/Editor/gitSync/useReconnectModalData.ts create mode 100644 app/client/src/ee/pages/Editor/gitSync/useReconnectModalData.ts rename app/client/src/pages/Editor/gitSync/{ImportedAppSuccessModal.tsx => ImportSuccessModal.tsx} (73%) diff --git a/app/client/src/ce/actions/workspaceActions.ts b/app/client/src/ce/actions/workspaceActions.ts index a3b3cc1db5..b061770c6a 100644 --- a/app/client/src/ce/actions/workspaceActions.ts +++ b/app/client/src/ce/actions/workspaceActions.ts @@ -129,3 +129,7 @@ export const fetchEntitiesOfWorkspace = (payload: { workspaceId?: string }) => { payload, }; }; + +export const resetImportData = () => ({ + type: ReduxActionTypes.RESET_IMPORT_DATA, +}); diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index 0521c7a384..b7374f14f6 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -546,6 +546,7 @@ const ActionTypes = { IMPORT_APPLICATION_FROM_GIT_INIT: "IMPORT_APPLICATION_FROM_GIT_INIT", IMPORT_APPLICATION_SUCCESS: "IMPORT_APPLICATION_SUCCESS", SET_WIDGET_LOADING: "SET_WIDGET_LOADING", + RESET_IMPORT_DATA: "RESET_IMPORT_DATA", SET_GLOBAL_SEARCH_QUERY: "SET_GLOBAL_SEARCH_QUERY", SET_GLOBAL_SEARCH_CATEGORY: "SET_GLOBAL_SEARCH_CATEGORY", TOGGLE_SHOW_GLOBAL_SEARCH_MODAL: "TOGGLE_SHOW_GLOBAL_SEARCH_MODAL", diff --git a/app/client/src/ce/pages/Editor/gitSync/useReconnectModalData.ts b/app/client/src/ce/pages/Editor/gitSync/useReconnectModalData.ts new file mode 100644 index 0000000000..9109ef39af --- /dev/null +++ b/app/client/src/ce/pages/Editor/gitSync/useReconnectModalData.ts @@ -0,0 +1,33 @@ +import { builderURL } from "@appsmith/RouteBuilder"; +import { + RECONNECT_MISSING_DATASOURCE_CREDENTIALS_DESCRIPTION, + SKIP_TO_APPLICATION, + createMessage, +} from "@appsmith/constants/messages"; +import { EditorNames } from "@appsmith/hooks"; + +interface UseReconnectModalDataProps { + pageId: string | null; + appId: string | null; +} + +function useReconnectModalData({ appId, pageId }: UseReconnectModalDataProps) { + const editorURL = + pageId && + builderURL({ + pageId, + }); + + return { + skipMessage: createMessage(SKIP_TO_APPLICATION), + missingDsCredentialsDescription: createMessage( + RECONNECT_MISSING_DATASOURCE_CREDENTIALS_DESCRIPTION, + ), + editorURL, + editorId: appId, + parentEntityId: pageId, + editorType: EditorNames.APPLICATION, + }; +} + +export default useReconnectModalData; diff --git a/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx b/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx index 73094e5741..f13ad3b2f0 100644 --- a/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx +++ b/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx @@ -247,6 +247,12 @@ export const handlers = { importingApplication: false, }; }, + [ReduxActionTypes.RESET_IMPORT_DATA]: (state: ApplicationsReduxState) => { + return { + ...state, + importedApplication: null, + }; + }, [ReduxActionTypes.PARTIAL_IMPORT_INIT]: (state: ApplicationsReduxState) => ({ ...state, partialImportExport: { diff --git a/app/client/src/ee/pages/Editor/gitSync/useReconnectModalData.ts b/app/client/src/ee/pages/Editor/gitSync/useReconnectModalData.ts new file mode 100644 index 0000000000..d111bbe2f1 --- /dev/null +++ b/app/client/src/ee/pages/Editor/gitSync/useReconnectModalData.ts @@ -0,0 +1,3 @@ +export * from "ce/pages/Editor/gitSync/useReconnectModalData"; +import { default as useCEReconnectModalData } from "ce/pages/Editor/gitSync/useReconnectModalData"; +export default useCEReconnectModalData; diff --git a/app/client/src/pages/Editor/gitSync/ImportedAppSuccessModal.tsx b/app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx similarity index 73% rename from app/client/src/pages/Editor/gitSync/ImportedAppSuccessModal.tsx rename to app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx index 7ac850e4a1..9aa6cd56f9 100644 --- a/app/client/src/pages/Editor/gitSync/ImportedAppSuccessModal.tsx +++ b/app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx @@ -27,8 +27,17 @@ const StyledModalContent = styled(ModalContent)` width: 640px; `; -function ImportedApplicationSuccessModal() { - const importedAppSuccess = localStorage.getItem("importApplicationSuccess"); +interface ImportSuccessModalProps { + title?: string; + description?: string; +} + +function ImportSuccessModal(props: ImportSuccessModalProps) { + const { + description = createMessage(APPLICATION_IMPORT_SUCCESS_DESCRIPTION), + title = createMessage(APPLICATION_IMPORT_SUCCESS), + } = props; + const importedAppSuccess = localStorage.getItem("importSuccess"); // const isOpen = importedAppSuccess === "true"; const [isOpen, setIsOpen] = useState(importedAppSuccess === "true"); @@ -40,7 +49,7 @@ function ImportedApplicationSuccessModal() { const close = () => { setIsOpen(false); - localStorage.setItem("importApplicationSuccess", "false"); + localStorage.setItem("importSuccess", "false"); }; return ( @@ -54,10 +63,8 @@ function ImportedApplicationSuccessModal() { name="success" size={"lg"} /> - - {createMessage(APPLICATION_IMPORT_SUCCESS)} - - {createMessage(APPLICATION_IMPORT_SUCCESS_DESCRIPTION)} + {title} + {description} @@ -76,4 +83,4 @@ function ImportedApplicationSuccessModal() { ); } -export default ImportedApplicationSuccessModal; +export default ImportSuccessModal; diff --git a/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx b/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx index f1e791a4f5..25fd58eb90 100644 --- a/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx +++ b/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx @@ -19,9 +19,7 @@ import { RECONNECT_DATASOURCE_SUCCESS_MESSAGE1, RECONNECT_DATASOURCE_SUCCESS_MESSAGE2, RECONNECT_MISSING_DATASOURCE_CREDENTIALS, - RECONNECT_MISSING_DATASOURCE_CREDENTIALS_DESCRIPTION, SKIP_CONFIGURATION, - SKIP_TO_APPLICATION, SKIP_TO_APPLICATION_TOOLTIP_DESCRIPTION, } from "@appsmith/constants/messages"; import { @@ -51,7 +49,6 @@ import { getOAuthAccessToken, loadFilePickerAction, } from "actions/datasourceActions"; -import { builderURL } from "@appsmith/RouteBuilder"; import localStorage from "utils/localStorage"; import { Modal, @@ -76,6 +73,9 @@ import { import type { AppState } from "@appsmith/reducers"; import { getFetchedWorkspaces } from "@appsmith/selectors/workspaceSelectors"; import { getApplicationsOfWorkspace } from "@appsmith/selectors/selectedWorkspaceSelectors"; +import useReconnectModalData from "@appsmith/pages/Editor/gitSync/useReconnectModalData"; +import { resetImportData } from "@appsmith/actions/workspaceActions"; +import history from "utils/history"; const Section = styled.div` display: flex; @@ -289,7 +289,6 @@ function ReconnectDatasourceModal() { >(queryDatasourceId); const [pageId, setPageId] = useState(queryPageId); const [appId, setAppId] = useState(queryAppId); - const [appURL, setAppURL] = useState(""); const [datasource, setDatasource] = useState(null); const [isImport, setIsImport] = useState(queryIsImport); const [isTesting, setIsTesting] = useState(false); @@ -312,6 +311,21 @@ function ReconnectDatasourceModal() { return output; }; + /** + * The role of useReconnectModalData is to provide editorId (appId or packageId), parentEntityId (pageId or moduleId) + * and any differentiating elements when a app vs package is imported. + * Right now it takes the pageId and appId and returns editorId/parentEntityId to reduces the changes required to + * refactor this for packages. Ideally the hook should calculate everything and return the necessary values. + */ + const { + editorId, + editorType, + editorURL, + missingDsCredentialsDescription, // pageId or moduleId + parentEntityId, // appId or packageId from query params + skipMessage, + } = useReconnectModalData({ pageId, appId }); + // when redirecting from oauth, processing the status if (isImport) { setIsImport(false); @@ -333,6 +347,7 @@ function ReconnectDatasourceModal() { workspaceId: orgId, datasourceName: dsName, pluginName: plugins[datasource?.pluginId || ""]?.name, + editorType, }); } else if (queryDatasourceId) { dispatch(loadFilePickerAction()); @@ -348,7 +363,7 @@ function ReconnectDatasourceModal() { if (app) { dispatch( setWorkspaceIdForImport({ - editorId: appId || "", + editorId: editorId || "", workspaceId: app.workspaceId, }), ); @@ -363,7 +378,7 @@ function ReconnectDatasourceModal() { dispatch({ type: ReduxActionTypes.FETCH_UNCONFIGURED_DATASOURCE_LIST, payload: { - applicationId: appId, + applicationId: editorId, workspaceId: app.workspaceId, }, }); @@ -428,15 +443,20 @@ function ReconnectDatasourceModal() { } }; + const clearImportData = () => { + dispatch(resetImportData()); + }; + const onClose = () => { localStorage.setItem("importedAppPendingInfo", "null"); dispatch(setIsReconnectingDatasourcesModalOpen({ isOpen: false })); dispatch( - setWorkspaceIdForImport({ editorId: appId || "", workspaceId: "" }), + setWorkspaceIdForImport({ editorId: editorId || "", workspaceId: "" }), ); dispatch(setPageIdForImport("")); dispatch(resetDatasourceConfigForImportFetchedFlag()); setSelectedDatasourceId(""); + clearImportData(); }; const onSelectDatasource = useCallback((ds: Datasource) => { @@ -478,17 +498,6 @@ function ReconnectDatasourceModal() { } }, [importedApplication, queryIsImport]); - useEffect(() => { - if (pageId) { - // TODO: Update route params here - setAppURL( - builderURL({ - pageId: pageId, - }), - ); - } - }, [pageId]); - // checking of full configured useEffect(() => { if (isModalOpen && !isTesting) { @@ -524,14 +533,14 @@ function ReconnectDatasourceModal() { } // When datasources are present and pending datasources are 0, // then only we want to update status as success - else if (appURL && pending.length === 0 && datasources.length > 0) { + else if (editorURL && pending.length === 0 && datasources.length > 0) { // open application import successfule - localStorage.setItem("importApplicationSuccess", "true"); + localStorage.setItem("importSuccess", "true"); localStorage.setItem("importedAppPendingInfo", "null"); - window.open(appURL, "_self"); + window.open(editorURL, "_self"); } } - }, [datasources, appURL, isModalOpen, isTesting, queryIsImport]); + }, [datasources, editorURL, isModalOpen, isTesting, queryIsImport]); const mappedDataSources = datasources.map((ds: Datasource) => { return ( @@ -551,6 +560,13 @@ function ReconnectDatasourceModal() { const shouldShowDBForm = isConfigFetched && !isLoading && !checkIfDatasourceIsConfigured(datasource); + const onSkipBtnClick = () => { + AnalyticsUtil.logEvent("RECONNECTING_SKIP_TO_APPLICATION_BUTTON_CLICK"); + localStorage.setItem("importedAppPendingInfo", "null"); + editorURL && history.push(editorURL); + onClose(); + }; + return ( - - {createMessage( - RECONNECT_MISSING_DATASOURCE_CREDENTIALS_DESCRIPTION, - )} - + {missingDsCredentialsDescription} {mappedDataSources} {shouldShowDBForm && ( )} {checkIfDatasourceIsConfigured(datasource) && SuccessMessages()} @@ -599,18 +611,12 @@ function ReconnectDatasourceModal() { diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index 1f43b5dfbe..366a6b8d2f 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -30,7 +30,7 @@ import { setupPage, updateCurrentPage } from "actions/pageActions"; import { getCurrentPageId } from "selectors/editorSelectors"; import { getSearchQuery } from "utils/helpers"; import RepoLimitExceededErrorModal from "./gitSync/RepoLimitExceededErrorModal"; -import ImportedApplicationSuccessModal from "./gitSync/ImportedAppSuccessModal"; +import ImportedApplicationSuccessModal from "./gitSync/ImportSuccessModal"; import { getIsBranchUpdated } from "../utils"; import { APP_MODE } from "entities/App"; import { GIT_BRANCH_QUERY_KEY } from "constants/routes"; From 99639d446e3ab73dd5d0432157a2f7d3440f4e33 Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Tue, 12 Mar 2024 18:14:05 +0530 Subject: [PATCH 09/25] fix: Homepage error message with no workspaces & Github changes message (#31691) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Fixing error message on homepage when there are no workspaces - Fixing leave workspace leading to no workspaces message - Fixing github changes list message on the git modal with modules & module instances - Adding doc link for packages Fixes [#30748](https://github.com/appsmithorg/appsmith/issues/30748) [#31472](https://github.com/appsmithorg/appsmith/issues/31472) [#30214](https://github.com/appsmithorg/appsmith/issues/30214) ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `6cd2ef6f4cfb2f12f251d6a4ad26e48fe88e78f8` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **New Features** - Added new categories (`PACKAGES`, `MODULES`, `MODULE_INSTANCES`) to track changes in Git Sync more effectively. - Introduced a new constant for accessing the packages overview documentation. - **Enhancements** - Improved icon determination logic for queries based on their configuration. - Enhanced user experience by redirecting to "/applications" after leaving a workspace. - **Refactor** - Optimized the `leaveWS` function for better performance. - Updated selectors and reducers to handle new Git Sync tracking categories. - **Tests** - Expanded test coverage to include tracking of modified packages, modules, and module instances. --- .../src/ce/pages/Applications/index.tsx | 17 ++++++++-------- app/client/src/ce/sagas/userSagas.tsx | 1 + .../useSource/useConnectToOptions.tsx | 14 ++++++------- .../src/constants/ThirdPartyConstants.tsx | 2 ++ .../gitSync/components/GitChangesList.tsx | 20 +++++++++++++++++++ .../src/reducers/uiReducers/gitSyncReducer.ts | 3 +++ app/client/src/selectors/gitSyncSelectors.tsx | 8 ++++++-- 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/app/client/src/ce/pages/Applications/index.tsx b/app/client/src/ce/pages/Applications/index.tsx index 14b6733899..140b7c20bb 100644 --- a/app/client/src/ce/pages/Applications/index.tsx +++ b/app/client/src/ce/pages/Applications/index.tsx @@ -12,7 +12,6 @@ import { createMessage, INVITE_USERS_PLACEHOLDER, NO_APPS_FOUND, - NO_WORKSPACE_DESCRIPTION, NO_WORKSPACE_HEADING, WORKSPACES_HEADING, } from "@appsmith/constants/messages"; @@ -565,11 +564,14 @@ export function ApplicationsSection(props: any) { setSelectedWorkspaceIdForImportApplication, ]); - const leaveWS = (workspaceId: string) => { - setWarnLeavingWorkspace(false); - setWorkspaceToOpenMenu(null); - dispatch(leaveWorkspace(workspaceId)); - }; + const leaveWS = useCallback( + (workspaceId: string) => { + setWarnLeavingWorkspace(false); + setWorkspaceToOpenMenu(null); + dispatch(leaveWorkspace(workspaceId)); + }, + [dispatch], + ); const handleDeleteWorkspace = useCallback( (workspaceId: string) => { @@ -657,9 +659,6 @@ export function ApplicationsSection(props: any) { {createMessage(NO_WORKSPACE_HEADING)} - - {createMessage(NO_WORKSPACE_DESCRIPTION)} - ); } diff --git a/app/client/src/ce/sagas/userSagas.tsx b/app/client/src/ce/sagas/userSagas.tsx index dc84d0f5b2..4439ea2df9 100644 --- a/app/client/src/ce/sagas/userSagas.tsx +++ b/app/client/src/ce/sagas/userSagas.tsx @@ -602,6 +602,7 @@ export function* leaveWorkspaceSaga( toast.show(`You have successfully left the workspace`, { kind: "success", }); + history.push("/applications"); } } catch (error) { // do nothing as it's already handled globally diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx index 17d202093a..2a781f7329 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx @@ -98,7 +98,13 @@ export const getQueryIcon = ( query: ActionData | ModuleInstanceData, pluginImages: Record, ) => { - if (!query.config.hasOwnProperty("sourceModuleId")) { + if (query.config.hasOwnProperty("type")) { + return ( + + + + ); + } else { const action = query as ActionData; return ( @@ -109,12 +115,6 @@ export const getQueryIcon = ( /> ); - } else { - return ( - - - - ); } }; diff --git a/app/client/src/constants/ThirdPartyConstants.tsx b/app/client/src/constants/ThirdPartyConstants.tsx index f03e68f827..f98268edb0 100644 --- a/app/client/src/constants/ThirdPartyConstants.tsx +++ b/app/client/src/constants/ThirdPartyConstants.tsx @@ -31,6 +31,8 @@ export const DOCS_BRANCH_PROTECTION_URL = "https://docs.appsmith.com/advanced-concepts/version-control-with-git/working-with-branches#branch-protection"; export const DOCS_DEFAULT_BRANCH_URL = "https://docs.appsmith.com/advanced-concepts/version-control-with-git/working-with-branches#default-branch"; +export const PACKAGES_OVERVIEW_DOC = + "https://docs.appsmith.com/packages/overview"; export const PRICING_PAGE_URL = ( URL: string, diff --git a/app/client/src/pages/Editor/gitSync/components/GitChangesList.tsx b/app/client/src/pages/Editor/gitSync/components/GitChangesList.tsx index 011417885c..1d4002cef7 100644 --- a/app/client/src/pages/Editor/gitSync/components/GitChangesList.tsx +++ b/app/client/src/pages/Editor/gitSync/components/GitChangesList.tsx @@ -57,6 +57,8 @@ export enum Kind { JS_LIB = "JS_LIB", THEME = "THEME", SETTINGS = "SETTINGS", + PACKAGES = "PACKAGES", + MODULES = "MODULES", } interface GitStatusProps { @@ -125,6 +127,22 @@ const STATUS_MAP: GitStatusMap = { iconName: "package", hasValue: (status?.modifiedJSLibs || 0) > 0, }), + [Kind.PACKAGES]: (status) => ({ + message: `${status?.modifiedPackages || 0} ${ + (status?.modifiedPackages || 0) <= 1 ? "package" : "packages" + } modified`, + iconName: "package", + hasValue: (status?.modifiedPackages || 0) > 0, + }), + [Kind.MODULES]: (status) => ({ + message: `${status?.modifiedModules || 0} ${ + (status?.modifiedModules || 0) <= 1 + ? "module configuration" + : "module configurations" + } modified`, + iconName: "package", + hasValue: (status?.modifiedModules || 0) > 0, + }), }; function behindCommitMessage(status: Partial) { @@ -193,6 +211,8 @@ export function gitChangeListData( Kind.JS_OBJECT, Kind.DATA_SOURCE, Kind.JS_LIB, + Kind.MODULES, + Kind.PACKAGES, ]; return changeKind .map((type: Kind) => STATUS_MAP[type](status)) diff --git a/app/client/src/reducers/uiReducers/gitSyncReducer.ts b/app/client/src/reducers/uiReducers/gitSyncReducer.ts index 5c28324c38..b69a7b9f06 100644 --- a/app/client/src/reducers/uiReducers/gitSyncReducer.ts +++ b/app/client/src/reducers/uiReducers/gitSyncReducer.ts @@ -670,6 +670,9 @@ export interface GitStatusData { modifiedJSLibs: number; discardDocUrl?: string; migrationMessage?: string; + modifiedPackages?: number; + modifiedModules?: number; + modifiedModuleInstances?: number; } interface GitErrorPayloadType { diff --git a/app/client/src/selectors/gitSyncSelectors.tsx b/app/client/src/selectors/gitSyncSelectors.tsx index d3b6efc307..68c3388953 100644 --- a/app/client/src/selectors/gitSyncSelectors.tsx +++ b/app/client/src/selectors/gitSyncSelectors.tsx @@ -135,8 +135,12 @@ export const getMergeError = (state: AppState) => state.ui.gitSync.mergeError; export const getCountOfChangesToCommit = (state: AppState) => { const gitStatus = getGitStatus(state); - const { modifiedPages = 0, modifiedQueries = 0 } = gitStatus || {}; - return modifiedPages + modifiedQueries; + const { + modifiedModules = 0, + modifiedPages = 0, + modifiedQueries = 0, + } = gitStatus || {}; + return modifiedPages + modifiedQueries + modifiedModules; }; export const getShowRepoLimitErrorModal = (state: AppState) => From de834b7142c2e9e1c2d57c76edc62f39d0d5cf5c Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Tue, 12 Mar 2024 18:43:00 +0530 Subject: [PATCH 10/25] chore: Side by Side analytics (#31690) ## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tags.Sanity" ### :mag: Cypress test results > [!CAUTION] > If you modify the content in this section, you are likely to disrupt the CI result for your PR. ## Summary by CodeRabbit - **New Features** - Enhanced analytics with the introduction of the "EDITOR_MODE_CHANGE" event to track changes in the editor's view mode. - Improved user experience in the IDE with the ability to track full-screen and split-screen mode changes through analytics. --- app/client/src/ce/sagas/NavigationSagas.ts | 4 ++++ app/client/src/ce/utils/analyticsUtilTypes.ts | 3 ++- .../IDE/EditorPane/components/SegmentedHeader.tsx | 13 +++++++++---- .../pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx | 4 ++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/client/src/ce/sagas/NavigationSagas.ts b/app/client/src/ce/sagas/NavigationSagas.ts index 2bc4822fd7..a7547c2304 100644 --- a/app/client/src/ce/sagas/NavigationSagas.ts +++ b/app/client/src/ce/sagas/NavigationSagas.ts @@ -20,8 +20,10 @@ import { flushErrors } from "actions/errorActions"; import type { NavigationMethod } from "utils/history"; import UsagePulse from "usagePulse"; import { getIDETypeByUrl } from "@appsmith/entities/IDE/utils"; +import type { EditorViewMode } from "@appsmith/entities/IDE/constants"; import { IDE_TYPE } from "@appsmith/entities/IDE/constants"; import { updateIDETabsOnRouteChangeSaga } from "sagas/IDESaga"; +import { getIDEViewMode } from "selectors/ideSelectors"; let previousPath: string; @@ -110,6 +112,7 @@ function* logNavigationAnalytics(payload: RouteChangeActionPayload) { const isRecent = recentEntityIds.some( (entityId) => entityId === currentEntity.id, ); + const ideViewMode: EditorViewMode = yield select(getIDEViewMode); const { height, width } = window.screen; AnalyticsUtil.logEvent("ROUTE_CHANGE", { toPath: pathname, @@ -121,6 +124,7 @@ function* logNavigationAnalytics(payload: RouteChangeActionPayload) { fromType: previousEntity.entity, screenHeight: height, screenWidth: width, + editorMode: ideViewMode, }); } diff --git a/app/client/src/ce/utils/analyticsUtilTypes.ts b/app/client/src/ce/utils/analyticsUtilTypes.ts index 00c1de8705..6fdfc40af1 100644 --- a/app/client/src/ce/utils/analyticsUtilTypes.ts +++ b/app/client/src/ce/utils/analyticsUtilTypes.ts @@ -354,7 +354,8 @@ export type EventName = | CUSTOM_WIDGET_EVENTS | "MULTI_FILE_PICKER_EXCEEDS_LIMIT" | "TEMPLATE_ADD_PAGE_FROM_TEMPLATE_FLOW" - | HOMEPAGE_CREATE_APP_FROM_TEMPLATE_EVENTS; + | HOMEPAGE_CREATE_APP_FROM_TEMPLATE_EVENTS + | "EDITOR_MODE_CHANGE"; type HOMEPAGE_CREATE_APP_FROM_TEMPLATE_EVENTS = | "TEMPLATE_DROPDOWN_CLICK" diff --git a/app/client/src/pages/Editor/IDE/EditorPane/components/SegmentedHeader.tsx b/app/client/src/pages/Editor/IDE/EditorPane/components/SegmentedHeader.tsx index c65805f011..6bc5bff456 100644 --- a/app/client/src/pages/Editor/IDE/EditorPane/components/SegmentedHeader.tsx +++ b/app/client/src/pages/Editor/IDE/EditorPane/components/SegmentedHeader.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useCallback } from "react"; import { Button, Flex, SegmentedControl, Tooltip } from "design-system"; import { createMessage, @@ -19,6 +19,7 @@ import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; import { getIDEViewMode, getIsSideBySideEnabled } from "selectors/ideSelectors"; import { setIdeEditorViewMode } from "actions/ideActions"; +import AnalyticsUtil from "../../../../../utils/AnalyticsUtil"; const Container = styled(Flex)` #editor-pane-segment-control { @@ -44,6 +45,12 @@ const SegmentedHeader = () => { }; const { segment } = useCurrentEditorState(); const { onSegmentChange } = useSegmentNavigation(); + const handleMaximizeButtonClick = useCallback(() => { + AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", { + to: EditorViewMode.FullScreen, + }); + dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen)); + }, []); return ( { id="editor-mode-maximize" isIconButton kind="tertiary" - onClick={() => - dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen)) - } + onClick={handleMaximizeButtonClick} startIcon="maximize-v3" /> diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx index 3f33cfd921..7fcc979a4b 100644 --- a/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx +++ b/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx @@ -18,6 +18,7 @@ import { MINIMIZE_BUTTON_TOOLTIP, createMessage, } from "@appsmith/constants/messages"; +import AnalyticsUtil from "utils/AnalyticsUtil"; const FullScreenTabs = () => { const dispatch = useDispatch(); @@ -26,6 +27,9 @@ const FullScreenTabs = () => { const { segment } = useCurrentEditorState(); const setSplitScreenMode = useCallback(() => { dispatch(setIdeEditorViewMode(EditorViewMode.SplitScreen)); + AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", { + to: EditorViewMode.SplitScreen, + }); }, []); const tabsConfig = TabSelectors[segment]; const pageId = useSelector(getCurrentPageId); From 1eb7f0e171db2f9b7154adacaea6a35e4b66913c Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Tue, 12 Mar 2024 18:54:39 +0530 Subject: [PATCH 11/25] chore: Remove "Save theme" functionality (#31481) This is deleting a defunct feature. [Slack thread](https://theappsmith.slack.com/archives/CGBPVEJ5C/p1709621165627549). --- .../ClientSide/ThemingTests/Basic_spec.js | 375 ++---------------- app/client/src/api/AppThemingApi.tsx | 17 - .../src/ce/constants/ReduxActionConstants.tsx | 2 - .../ThemePropertyPane/SaveThemeModal.tsx | 178 --------- .../Editor/ThemePropertyPane/ThemeEditor.tsx | 24 +- .../reducers/uiReducers/appThemingReducer.ts | 6 - app/client/src/sagas/AppThemingSaga.tsx | 34 -- .../controllers/ce/ThemeControllerCE.java | 10 - 8 files changed, 33 insertions(+), 613 deletions(-) delete mode 100644 app/client/src/pages/Editor/ThemePropertyPane/SaveThemeModal.tsx diff --git a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js index a7848fc963..e62d1ec529 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js @@ -167,247 +167,15 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { }); }); - it("3. Checks if the theme can be saved", () => { - //Click on dropDown elipses - cy.contains("Theme properties") - .closest("div") - .siblings() - .first() - .find("button") - .click({ force: true }); - - agHelper.AssertAutoSave(); - - //Click on save theme dropdown option - cy.contains("Save theme").click({ force: true }); - - //Type the name of the theme: - agHelper.TypeText("input[placeholder='My theme']", "testtheme"); - //Click on save theme button - agHelper.ClickButton("Save theme"); - agHelper.ValidateToastMessage("Theme testtheme saved"); - appSettings.ClosePane(); - }); - - it("4. Verify Save Theme after changing all properties & widgets conform to the selected theme", () => { - cy.dragAndDropToCanvas("iconbuttonwidget", { x: 300, y: 300 }); - cy.assertPageSave(); - cy.get("canvas").first(0).trigger("click", { force: true }); - - appSettings.OpenAppSettings(); - appSettings.GoToThemeSettings(); - //#region Change Font & verify widgets: - - agHelper.GetNClick(".rc-select-selection-search-input").then(($elem) => { - cy.get($elem).click({ force: true }); - cy.wait(250); - cy.get(".rc-virtual-list-holder div") - .children() - .eq(4) - .then(($childElem) => { - cy.get($childElem).click({ force: true }); - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "font-family", - `${$childElem.children().last().text()}Inter, sans-serif`, - ); - cy.get(widgetsPage.widgetBtn).should( - "have.css", - "font-family", - `${$childElem.children().last().text()}Inter, sans-serif`, - ); - }); - }); - - cy.get(widgetsPage.colorPickerV2Popover).click({ force: true }).click(); - cy.get(widgetsPage.colorPickerV2Color) - .eq(-15) - .then(($elem) => { - cy.get($elem).click({ force: true }); - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "background-color", - $elem.css("background-color"), - ); - cy.get(widgetsPage.widgetBtn).should( - "have.css", - "background-color", - $elem.css("background-color"), - ); - }); - - //Change the background color: - cy.get("[data-testid='theme-backgroundColor']").click({ force: true }); - cy.wait(500); - cy.get(widgetsPage.colorPickerV2Popover).click({ force: true }).click(); - cy.get(widgetsPage.colorPickerV2TailwindColor) - .eq(23) - .then(($elem) => { - cy.get($elem).click({ force: true }); - cy.get(commonlocators.canvas).should( - "have.css", - "background-color", - $elem.css("background-color"), - ); - }); - - cy.get(commonlocators.themeAppBorderRadiusBtn).eq(2).click({ force: true }); - cy.get(`${commonlocators.themeAppBorderRadiusBtn}`) - .eq(2) - .invoke("css", "border-top-left-radius") - .then((borderRadius) => { - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "border-radius", - borderRadius, - ); - cy.get(widgetsPage.widgetBtn).should( - "have.css", - "border-radius", - borderRadius, - ); - }); - - //#region Change the shadow & verify widgets - cy.get("[data-value='L']").eq(1).click({ force: true }); - cy.get("[data-value='L']") - .eq(1) - .invoke("css", "box-shadow") - .then((boxShadow) => { - cy.get(containerShadowElement).should( - "have.css", - "box-shadow", - boxShadow, - ); - }); - - //#region Click on dropDown elipses - cy.contains("Theme properties") - .closest("div") - .siblings() - .first() - .find("button") - .click({ force: true }); - cy.wait(300); - - //Click on save theme dropdown option & close it - cy.contains("Save theme").click({ force: true }); - cy.wait(200); - cy.get(".ads-v2-modal__content-header-close-button").click(); - - //Click on save theme dropdown option & cancel it - cy.contains("Theme properties") - .closest("div") - .siblings() - .first() - .find("button") - .click({ force: true }); - cy.wait(300); - cy.contains("Save theme").click({ force: true }); - cy.wait(200); - cy.xpath("//span[text()='Cancel']/parent::div").click(); - - //Click on save theme dropdown option, give duplicte name & save it - cy.contains("Theme properties") - .closest("div") - .siblings() - .first() - .find("button") - .click({ force: true }); - cy.wait(300); - cy.contains("Save theme").click({ force: true }); - cy.wait(200); - //Type the name of the theme: - agHelper.TypeText("input[placeholder='My theme']", "testtheme"); - cy.contains("Name must be unique"); - - cy.get("input[placeholder='My theme']").clear().type("VioletYellowTheme"); - - //Click on save theme button - agHelper.ClickButton("Save theme"); - agHelper.ValidateToastMessage("Theme VioletYellowTheme saved"); - }); - - it("5. Verify Themes exists under respective section when ChangeTheme button is cicked in properties with Apply Theme & Trash as applicable", () => { - //Click on change theme: + it("4. Verify user able to change between saved theme & already existing Featured themes", () => { cy.get(commonlocators.changeThemeBtn).click({ force: true }); - cy.xpath(applyTheme("Your themes", "testtheme")) - .click({ force: true }) - .wait(1000); //Changing to testtheme - cy.contains("Applied theme") - .click() - .parent() - .siblings() - .find(".t--theme-card > main > main") - .invoke("css", "background-color") - .then((backgroudColor) => { - expect(backgroudColor).to.eq("rgb(236, 72, 153)"); - }); - - //Check if the saved theme is present under 'Yours Themes' section with Trash button - cy.xpath(applyTheme("Your themes", "testtheme")).should("exist"); - cy.xpath(themesDeletebtn("Your themes", "testtheme")).should("exist"); - - cy.xpath(applyTheme("Your themes", "VioletYellowTheme")).should("exist"); - cy.xpath(themesDeletebtn("Your themes", "VioletYellowTheme")).should( - "exist", - ); - - cy.xpath(applyTheme("Featured themes", "Earth")).should("exist"); - cy.xpath(themesDeletebtn("Featured themes", "Earth")).should("not.exist"); - - cy.xpath(applyTheme("Featured themes", "Sunrise")).should("exist"); - cy.xpath(themesDeletebtn("Featured themes", "Sunrise")).should("not.exist"); - - cy.xpath(applyTheme("Featured themes", "Pacific")).should("exist"); - cy.xpath(themesDeletebtn("Featured themes", "Pacific")).should("not.exist"); - - cy.xpath(applyTheme("Featured themes", "Pampas")).should("exist"); - cy.xpath(themesDeletebtn("Featured themes", "Pampas")).should("not.exist"); - }); - - it("6. Verify the custom theme can be deleted", () => { - //Delete the created theme - cy.xpath(themesDeletebtn("Your themes", "testtheme")) - .click({ force: true }) - .wait(200); - cy.contains( - "Do you really want to delete this theme? This process cannot be undone.", - ); - - //Click on Delete theme trash icon & close it - cy.xpath("//*[text()='Are you sure?']/following-sibling::button").click(); - cy.get(commonlocators.toastMsg).should("not.exist"); - - //Click on Delete theme trash icon & cancel it - cy.xpath(themesDeletebtn("Your themes", "testtheme")) - .click({ force: true }) - .wait(200); - cy.xpath("//span[text()='No']/parent::div").click(); - cy.get(commonlocators.toastMsg).should("not.exist"); - - //Click on Delete theme trash icon & delete it - cy.xpath(themesDeletebtn("Your themes", "testtheme")) - .click({ force: true }) - .wait(200); - agHelper.ClickButton("Delete"); - // cy.contains("Delete").click({ force: true }); - - //check for delete alert - // cy.wait(500); - agHelper.ValidateToastMessage("Theme testtheme deleted"); - //cy.get(commonlocators.toastMsg).contains("Theme testtheme deleted"); - cy.xpath(applyTheme("Your themes", "testtheme")).should("not.exist"); - }); - - it("7. Verify user able to change between saved theme & already existing Featured themes", () => { //#region Pampas cy.xpath(applyTheme("Featured themes", "Pampas")) .click({ force: true }) .wait(1000); //Changing to one of Featured themes cy.contains("Applied theme") - // .click() + .click() .parent() .siblings() .find(".t--theme-card > main > section > div > main") @@ -620,70 +388,38 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { expect(backgroudColor).to.eq("rgb(248, 250, 252)"); }); //#endregion - - //#region VioletYellowTheme - cy.xpath(applyTheme("Your themes", "VioletYellowTheme")) - .click({ force: true }) - .wait(1000); //Changing to created test theme - - cy.contains("Applied theme") - // .click() - .parent() - .siblings() - .find(".t--theme-card > main > section > div > main") - .eq(0) - .invoke("css", "background-color") - .then((backgroudColor) => { - expect(backgroudColor).to.eq("rgb(219, 234, 254)"); - }); - - cy.contains("Applied theme") - // .click() - .parent() - .siblings() - .find(".t--theme-card > main > section > div > main") - .eq(1) - .invoke("css", "background-color") - .then((backgroudColor) => { - expect(backgroudColor).to.eq("rgb(29, 78, 216)"); - }); - - //#endregion }); - it("8. Verify widgets conform to the selected theme in Publish mode", () => { + it("5. Verify widgets conform to the selected theme in Publish mode", () => { deployMode.DeployApp(); //cy.wait(4000); //for theme to settle - cy.get("body").should("have.css", "font-family", "Inter, sans-serif"); //Font + cy.get("body").should( + "have.css", + "font-family", + `"Nunito Sans", sans-serif`, + ); //Font cy.xpath("//div[@id='root']//section/parent::div").should( "have.css", "background-color", - "rgb(29, 78, 216)", + "rgb(248, 250, 252)", ); //Background Color cy.get(widgetsPage.widgetBtn).should( "have.css", "background-color", - "rgb(219, 234, 254)", - ); //Widget Color - cy.get(publish.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(219, 234, 254)", + "rgb(100, 116, 139)", ); //Widget Color - cy.get(widgetsPage.widgetBtn).should("have.css", "border-radius", "24px"); //Border Radius - cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px"); //Border Radius + cy.get(widgetsPage.widgetBtn).should("have.css", "border-radius", "0px"); //Border Radius cy.get(widgetsPage.widgetBtn).should("have.css", "box-shadow", "none"); //Shadow - cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow deployMode.NavigateBacktoEditor(); }); - it("9. Verify Adding new Individual widgets & it can change Color, Border radius, Shadow & can revert [Color/Border Radius] to already selected theme", () => { + it("6. Verify Adding new Individual widgets & it can change Color, Border radius, Shadow & can revert [Color/Border Radius] to already selected theme", () => { cy.dragAndDropToCanvas("buttonwidget", { x: 200, y: 400 }); //another button widget cy.moveToStyleTab(); //Change Color & verify @@ -701,13 +437,8 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { cy.get(".t--widget-button1 button").should( "have.css", "background-color", - "rgb(219, 234, 254)", + "rgb(100, 116, 139)", ); //old widgets still conforming to theme color - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(219, 234, 254)", - ); }); //Change Border & verify @@ -722,22 +453,16 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "border-radius", borderRadius, //0px ); - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "border-radius", - "24px", - ); cy.get(".t--widget-button1 button").should( "have.css", "border-radius", - "24px", + "0px", ); }); //Change Shadow & verify cy.contains(".ads-v2-segmented-control-value-0", "Large").click(); - cy.get(widgetsPage.iconWidgetBtn).should("have.css", "box-shadow", "none"); cy.get(".t--widget-button1 button").should( "have.css", "box-shadow", @@ -748,23 +473,17 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { deployMode.DeployApp(); //Verify Background color - cy.get(".t--widget-buttonwidget:nth-child(4) button").should( + cy.get(".t--widget-button2 button").should( "have.css", "background-color", "rgb(190, 24, 93)", ); //new widget with its own color ////old widgets still conforming to theme color - cy.get(".t--widget-buttonwidget button").should( + cy.get(".t--widget-button1 button").should( "have.css", "background-color", - "rgb(219, 234, 254)", - ); - - cy.get(publish.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(219, 234, 254)", + "rgb(100, 116, 139)", ); //Verify Border radius @@ -773,11 +492,10 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "border-radius", "0px", ); - cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px"); cy.get(".t--widget-button1 button").should( "have.css", "border-radius", - "24px", + "0px", ); //Verify Box shadow @@ -786,7 +504,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "box-shadow", "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", ); - cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); cy.get(".t--widget-button1 button").should( "have.css", "box-shadow", @@ -805,7 +522,7 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { cy.get(".t--widget-button2 button").should( "have.css", "background-color", - "rgb(219, 234, 254)", + "rgb(100, 116, 139)", ); //verify widget reverted to theme color cy.get(".t--property-control-borderradius .reset-button").then(($elem) => { $elem[0].removeAttribute("display: none"); @@ -814,24 +531,28 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { cy.get(".t--widget-button2 button").should( "have.css", "border-radius", - "24px", + "0px", ); //the new widget with reverted styles also conforming to theme deployMode.DeployApp(); cy.wait(4000); //for theme to settle - cy.get("body").should("have.css", "font-family", "Inter, sans-serif"); //Font + cy.get("body").should( + "have.css", + "font-family", + `"Nunito Sans", sans-serif`, + ); //Font cy.xpath("//div[@id='root']//section/parent::div").should( "have.css", "background-color", - "rgb(29, 78, 216)", + "rgb(248, 250, 252)", ); //Background Color cy.get(".t--widget-button1 button").should( "have.css", "background-color", - "rgb(219, 234, 254)", + "rgb(100, 116, 139)", ); //Widget Color cy.get("body").then(($ele) => { if ($ele.find(widgetsPage.widgetBtn).length <= 1) { @@ -842,25 +563,19 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { cy.get(".t--widget-button2 button").should( "have.css", "background-color", - "rgb(219, 234, 254)", - ); //Widget Color - cy.get(publish.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(219, 234, 254)", + "rgb(100, 116, 139)", ); //Widget Color cy.get(".t--widget-button1 button").should( "have.css", "border-radius", - "24px", + "0px", ); //Border Radius cy.get(".t--widget-button2 button").should( "have.css", "border-radius", - "24px", + "0px", ); //Border Radius - cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px"); //Border Radius cy.get(".t--widget-button1 button").should( "have.css", @@ -872,12 +587,10 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "box-shadow", "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", ); //Since Shadow revert option does not exixts - cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow - deployMode.NavigateBacktoEditor(); }); - it("10. Verify Chainging theme should not affect Individual widgets with changed Color, Border radius, Shadow & can revert to newly selected theme", () => { + it("7. Verify Chainging theme should not affect Individual widgets with changed Color, Border radius, Shadow & can revert to newly selected theme", () => { cy.get("canvas").first(0).trigger("click", { force: true }); appSettings.OpenAppSettings(); @@ -911,11 +624,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "background-color", "rgb(239, 68, 68)", ); //old widgets still conforming to theme color - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(239, 68, 68)", - ); }); //Change Border & verify @@ -930,11 +638,7 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "border-radius", borderRadius, //6px ); - cy.get(widgetsPage.iconWidgetBtn).should( - "have.css", - "border-radius", - "24px", - ); + cy.get(".t--widget-button2 button").should( "have.css", "border-radius", @@ -944,7 +648,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { //Change Shadow & verify cy.contains(".ads-v2-segmented-control-value-0", "Small").click(); - cy.get(widgetsPage.iconWidgetBtn).should("have.css", "box-shadow", "none"); cy.get(".t--widget-button2 button").should( "have.css", "box-shadow", @@ -971,11 +674,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "background-color", "rgb(239, 68, 68)", ); - cy.get(publish.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(239, 68, 68)", - ); //Verify Border radius cy.get(".t--widget-button1 button").should( @@ -983,7 +681,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "border-radius", "6px", ); - cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px"); cy.get(".t--widget-button2 button").should( "have.css", "border-radius", @@ -996,7 +693,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "box-shadow", "rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px", ); - cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); cy.get(".t--widget-button2 button").should( "have.css", "box-shadow", @@ -1056,11 +752,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "background-color", "rgb(239, 68, 68)", ); //Widget Color - cy.get(publish.iconWidgetBtn).should( - "have.css", - "background-color", - "rgb(239, 68, 68)", - ); //Widget Color cy.get(".t--widget-button1 button").should( "have.css", @@ -1072,7 +763,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "border-radius", "24px", ); //Border Radius - cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px"); //Border Radius cy.get(".t--widget-button1 button").should( "have.css", @@ -1084,7 +774,6 @@ describe("App Theming funtionality", { tags: ["@tag.Theme"] }, function () { "box-shadow", "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", ); //Since Shadow revert option does not exixts - cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow deployMode.NavigateBacktoEditor(); }); diff --git a/app/client/src/api/AppThemingApi.tsx b/app/client/src/api/AppThemingApi.tsx index 39969d6135..695c5b2583 100644 --- a/app/client/src/api/AppThemingApi.tsx +++ b/app/client/src/api/AppThemingApi.tsx @@ -68,23 +68,6 @@ class AppThemingApi extends API { ); } - /** - * fires api for saving current theme - * - * @param applicationId - * @param theme - * @returns - */ - static async saveTheme( - applicationId: string, - payload: { name: string }, - ): Promise>> { - return API.patch( - `${AppThemingApi.baseUrl}/themes/applications/${applicationId}`, - payload, - ); - } - /** * fires api for deleting theme * diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index b7374f14f6..4077a4ad75 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -688,7 +688,6 @@ const ActionTypes = { CHANGE_SELECTED_APP_THEME_SUCCESS: "CHANGE_SELECTED_APP_THEME_SUCCESS", SET_PREVIEW_APP_THEME: "SET_PREVIEW_APP_THEME", SAVE_APP_THEME_INIT: "SAVE_APP_THEME_INIT", - SAVE_APP_THEME_SUCCESS: "SAVE_APP_THEME_SUCCESS", DELETE_APP_THEME_INIT: "DELETE_APP_THEME_INIT", DELETE_APP_THEME_SUCCESS: "DELETE_APP_THEME_SUCCESS", RESET_APP_THEME_INIT: "RESET_APP_THEME_INIT", @@ -1079,7 +1078,6 @@ export const ReduxActionErrorTypes = { UPDATE_JS_FUNCTION_PROPERTY_ERROR: "UPDATE_JS_FUNCTION_PROPERTY_ERROR", DELETE_WORKSPACE_ERROR: "DELETE_WORKSPACE_ERROR", REFLOW_BETA_FLAGS_INIT_ERROR: "REFLOW_BETA_FLAGS_INIT_ERROR", - SAVE_APP_THEME_ERROR: "SAVE_APP_THEME_ERROR", DELETE_APP_THEME_ERROR: "DELETE_APP_THEME_ERROR", GET_ALL_TEMPLATES_ERROR: "GET_ALL_TEMPLATES_ERROR", GET_SIMILAR_TEMPLATES_ERROR: "GET_SIMILAR_TEMPLATES_ERROR", diff --git a/app/client/src/pages/Editor/ThemePropertyPane/SaveThemeModal.tsx b/app/client/src/pages/Editor/ThemePropertyPane/SaveThemeModal.tsx deleted file mode 100644 index f8b67ad7f6..0000000000 --- a/app/client/src/pages/Editor/ThemePropertyPane/SaveThemeModal.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import React, { useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; - -import AnalyticsUtil from "utils/AnalyticsUtil"; -import { saveSelectedThemeAction } from "actions/appThemingActions"; -import { getCurrentApplicationId } from "selectors/editorSelectors"; -import { getAppThemes } from "selectors/appThemingSelectors"; -import { - createMessage, - ERROR_MESSAGE_NAME_EMPTY, - APLHANUMERIC_HYPHEN_SLASH_SPACE_ERROR, - UNIQUE_NAME_ERROR, -} from "@appsmith/constants/messages"; -import { - Button, - Input, - Text, - Modal, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, -} from "design-system"; - -interface SaveThemeModalProps { - isOpen: boolean; - onClose(): void; -} - -function SaveThemeModal(props: SaveThemeModalProps) { - const { isOpen } = props; - const dispatch = useDispatch(); - const [name, setName] = useState(""); - const [inputValidator, setInputValidator] = useState({ - isValid: false, - message: "", - isDirty: false, - }); - const applicationId = useSelector(getCurrentApplicationId); - const themes = useSelector(getAppThemes); - - /** - * dispatches action to save selected theme - * - */ - const onSubmit = (event: any) => { - event.preventDefault(); - - // if input validations fails, don't do anything - if (!inputValidator.isValid || inputValidator.isDirty === false) return; - - AnalyticsUtil.logEvent("APP_THEMING_SAVE_THEME_SUCCESS", { - themeName: name, - }); - - dispatch(saveSelectedThemeAction({ applicationId, name })); - - // close the modal after submit - onClose(); - }; - - /** - * theme creation validator - * - * @param value - * @returns - */ - const createThemeValidator = (value: string) => { - let isValid = !!value; - - let errorMessage = !isValid ? createMessage(ERROR_MESSAGE_NAME_EMPTY) : ""; - - if ( - isValid && - themes.find((theme) => value.toLowerCase() === theme.name.toLowerCase()) - ) { - isValid = false; - errorMessage = createMessage(UNIQUE_NAME_ERROR); - } - - if (/[^a-zA-Z0-9\-\/\ ]/.test(value)) { - isValid = false; - errorMessage = createMessage(APLHANUMERIC_HYPHEN_SLASH_SPACE_ERROR); - } - - return { - isValid: isValid, - message: errorMessage, - isDirty: true, - }; - }; - - /** - * on input change - * - * @param value - */ - const onChangeName = (value: string) => { - const validator = createThemeValidator(value); - - setInputValidator(validator); - setName(value); - }; - - /** - * on close modal - */ - const onClose = () => { - // reset validations - setInputValidator({ - isValid: false, - message: "", - isDirty: false, - }); - - props.onClose(); - }; - - return ( - { - if (!isOpen) { - onClose(); - } - }} - open={isOpen} - > - { - e.preventDefault(); - }} - style={{ width: "640px" }} - > - Save theme - -
- - You can save your custom themes to use across applications and use - them when you need. - -
- -
-
-
- -
- - -
-
-
-
- ); -} - -export default SaveThemeModal; diff --git a/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx b/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx index 3cab5935d5..635ddbcabc 100644 --- a/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx +++ b/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx @@ -1,7 +1,7 @@ import styled, { createGlobalStyle } from "styled-components"; import { get, startCase } from "lodash"; import { useDispatch, useSelector } from "react-redux"; -import React, { useCallback, useState } from "react"; +import React, { useCallback } from "react"; import ThemeCard from "./ThemeCard"; import { @@ -15,7 +15,6 @@ import { updateSelectedAppThemeAction, } from "actions/appThemingActions"; import SettingSection from "./SettingSection"; -import SaveThemeModal from "./SaveThemeModal"; import type { AppTheme } from "entities/AppTheming"; import AnalyticsUtil from "utils/AnalyticsUtil"; import ThemeFontControl from "./controls/ThemeFontControl"; @@ -64,7 +63,6 @@ function ThemeEditor() { const applicationId = useSelector(getCurrentApplicationId); const selectedTheme = useSelector(getSelectedAppTheme); const themingStack = useSelector(getAppThemingStack); - const [isSaveModalOpen, setSaveModalOpen] = useState(false); /** * customizes the current theme @@ -95,22 +93,6 @@ function ThemeEditor() { ); }, [setAppThemingModeStackAction]); - /** - * open the save modal - */ - const onOpenSaveModal = useCallback(() => { - AnalyticsUtil.logEvent("APP_THEMING_SAVE_THEME_START"); - - setSaveModalOpen(true); - }, [setSaveModalOpen]); - - /** - * on close save modal - */ - const onCloseSaveModal = useCallback(() => { - setSaveModalOpen(false); - }, [setSaveModalOpen]); - /** * resets theme */ @@ -136,9 +118,6 @@ function ThemeEditor() { /> - - Save theme - Reset widget styles @@ -270,7 +249,6 @@ function ThemeEditor() { )} - ); diff --git a/app/client/src/reducers/uiReducers/appThemingReducer.ts b/app/client/src/reducers/uiReducers/appThemingReducer.ts index af37ad8338..c26b40ff3d 100644 --- a/app/client/src/reducers/uiReducers/appThemingReducer.ts +++ b/app/client/src/reducers/uiReducers/appThemingReducer.ts @@ -111,12 +111,6 @@ const themeReducer = createImmerReducer(initialState, { (theme) => theme.id !== action.payload.themeId, ); }, - [ReduxActionTypes.SAVE_APP_THEME_SUCCESS]: ( - state: AppThemingState, - action: ReduxAction, - ) => { - state.themes.push(action.payload); - }, [ReduxActionTypes.UPDATE_BETA_CARD_SHOWN]: ( state: AppThemingState, action: ReduxAction, diff --git a/app/client/src/sagas/AppThemingSaga.tsx b/app/client/src/sagas/AppThemingSaga.tsx index 92b83d71d0..476e2e1a8f 100644 --- a/app/client/src/sagas/AppThemingSaga.tsx +++ b/app/client/src/sagas/AppThemingSaga.tsx @@ -3,7 +3,6 @@ import type { DeleteAppThemeAction, FetchAppThemesAction, FetchSelectedAppThemeAction, - SaveAppThemeAction, UpdateSelectedAppThemeAction, } from "actions/appThemingActions"; import { updateisBetaCardShownAction } from "actions/appThemingActions"; @@ -19,7 +18,6 @@ import { CHANGE_APP_THEME, createMessage, DELETE_APP_THEME, - SAVE_APP_THEME, SET_DEFAULT_SELECTED_THEME, } from "@appsmith/constants/messages"; import { ENTITY_TYPE } from "@appsmith/entities/AppsmithConsole/utils"; @@ -225,37 +223,6 @@ export function* changeSelectedTheme( } } -/** - * save and create new theme from selected theme - * - * @param action - */ -export function* saveSelectedTheme(action: ReduxAction) { - const { applicationId, name } = action.payload; - - try { - const response: ApiResponse = yield ThemingApi.saveTheme( - applicationId, - { name }, - ); - - yield put({ - type: ReduxActionTypes.SAVE_APP_THEME_SUCCESS, - payload: response.data, - }); - - // shows toast - toast.show(createMessage(SAVE_APP_THEME, name), { - kind: "success", - }); - } catch (error) { - yield put({ - type: ReduxActionErrorTypes.SAVE_APP_THEME_ERROR, - payload: { error }, - }); - } -} - /** * deletes custom saved theme * @@ -359,7 +326,6 @@ export default function* appThemingSaga() { ReduxActionTypes.CHANGE_SELECTED_APP_THEME_INIT, changeSelectedTheme, ), - takeLatest(ReduxActionTypes.SAVE_APP_THEME_INIT, saveSelectedTheme), takeLatest(ReduxActionTypes.DELETE_APP_THEME_INIT, deleteTheme), takeLatest(ReduxActionTypes.CLOSE_BETA_CARD_SHOWN, closeisBetaCardShown), takeLatest( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ThemeControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ThemeControllerCE.java index 21505570c5..95c12e8020 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ThemeControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ThemeControllerCE.java @@ -68,16 +68,6 @@ public class ThemeControllerCE extends BaseController new ResponseDTO<>(HttpStatus.OK.value(), theme, null)); } - @JsonView(Views.Public.class) - @PatchMapping("applications/{applicationId}") - public Mono> publishCurrentTheme( - @PathVariable String applicationId, - @RequestBody Theme resource, - @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) { - return service.persistCurrentTheme(applicationId, branchName, resource) - .map(theme -> new ResponseDTO<>(HttpStatus.OK.value(), theme, null)); - } - @JsonView(Views.Public.class) @PatchMapping("{themeId}") public Mono> updateName(@PathVariable String themeId, @Valid @RequestBody Theme resource) { From efce75ceb64683dcc2b6e13e3884e6bdfd802a88 Mon Sep 17 00:00:00 2001 From: Gurudatt S A Date: Tue, 12 Mar 2024 19:18:36 +0530 Subject: [PATCH 12/25] fix: Added index.d.ts file to enable auto code completion for custom commands in Cypress tests (#31696) Co-authored-by: Gurudatt SA <> --- app/client/cypress/support/index.d.ts | 179 ++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 app/client/cypress/support/index.d.ts diff --git a/app/client/cypress/support/index.d.ts b/app/client/cypress/support/index.d.ts new file mode 100644 index 0000000000..2126de3a5b --- /dev/null +++ b/app/client/cypress/support/index.d.ts @@ -0,0 +1,179 @@ +/// + +declare namespace Cypress { + interface Chainable { + SignupFromAPI(uname: string, password: string); + dragTo(subject: any, targetEl: any); + downloadData(filetype: string); + validateDownload(fileName: string); + AddFilterWithOperator( + operator: string, + option: string, + condition: string, + value: string, + ); + stubPostHeaderReq(); + addOAuth2ClientCredentialsDetails( + accessTokenUrl: string, + clientId: string, + clientSecret: string, + scope: string, + ); + addOAuth2AuthorizationCodeDetails( + accessTokenUrl: string, + clientId: string, + clientSecret: string, + authURL: string, + ); + testSelfSignedCertificateSettingsInREST(isOAuth2: boolean); + addBasicProfileDetails(username: string, password: string); + DeleteApp(appName: string); + GetUrlQueryParams(); + LogOutUser(); + LoginUser(uname: string, pword: string, goToLoginPage?: boolean); + LogintoApp(uname: string, pword: string); + LogintoAppTestUser(uname: string, pword: string); + Signup(uname: string, pword: string); + LoginFromAPI(uname: string, pword: string); + DeletepageFromSideBar(); + LogOut(toCheckgetPluginForm?: boolean); + SearchApp(appname: string); + WaitAutoSave(); + SelectAction(action: string); + ClearSearch(); + paste($element: any, text: string); + clickTest(testbutton: string); + EvaluateCurrentValue( + currentValue: string, + isValueToBeEvaluatedDynamic?: boolean, + ); + tabPopertyUpdate(tabId: string, newTabName: string); + generateUUID(); + addDsl(dsl: any); + DeleteAppByApi(); + DeleteWorkspaceByApi(); + togglebar(value: string); + radiovalue(value: string, value2: string); + optionValue(value: string, value2: string); + typeIntoDraftEditor(selector: string, text: string); + getPluginFormsAndCreateDatasource(); + NavigateToJSEditor(); + importCurl(); + selectAction(option: string); + deleteActionAndConfirm(); + deleteJSObject(); + deleteDataSource(); + dragAndDropToCanvas(widgetType: string, { x: number, y: number }); + dragAndDropToWidget( + widgetType: string, + destinationWidget: string, + { x: number, y: number }, + ); + dragAndDropToWidgetBySelector( + widgetType: string, + destinationSelector: string, + { x: number, y: number }, + ); + changeButtonColor(buttonColor: string); + closePropertyPane(); + onClickActions( + forSuccess: string, + forFailure: string, + actionType: string, + actionValue: string, + idx?: number, + ); + isSelectRow(index: number); + getDate(date: number, dateFormate: string); + setDate(date: number, dateFormate: string); + pageNo(); + pageNoValidate(index: number); + validateDisableWidget(widgetCss: string, disableCss: string); + validateToolbarVisible(widgetCss: string, toolbarCss: string); + validateToolbarHidden(widgetCss: string, toolbarCss: string); + validateEnableWidget(widgetCss: string, disableCss: string); + validateHTMLText(widgetCss: string, htmlTag: string, value: string); + setTinyMceContent(tinyMceId: string, content: string); + startRoutesForDatasource(); + startServerAndRoutes(); + startErrorRoutes(); + NavigateToPaginationTab(); + ValidateTableData(value: string); + ValidateTableV2Data(value: string); + ValidatePublishTableData(value: string); + ValidatePublishTableV2Data(value: string); + ValidatePaginateResponseUrlData(runTestCss: string); + ValidatePaginateResponseUrlDataV2(runTestCss: string); + ValidatePaginationInputData(valueToTest: string); + ValidatePaginationInputDataV2(valueToTest: string); + CheckForPageSaveError(); + assertPageSave(validateSavedState?: boolean); + validateCodeEditorContent(selector: string, contentToValidate: string); + updateMapType(mapType: string); + createJSObject(JSCode: string); + createSuperUser(); + SignupFromAPI(uname: string, pword: string); + startInterceptRoutesForMySQL(); + startInterceptRoutesForMongo(); + startInterceptRoutesForS3(); + replaceApplicationIdForInterceptPages(fixtureFile: string); + paste(selector: string, pastePayload: string); + typeValueNValidate( + valueToType: string, + fieldName?: string, + isDynamic?: boolean, + ); + checkCodeInputValue(selector: string); + clickButton(btnVisibleText: string, toForceClick?: boolean); + actionContextMenuByEntityName( + entityNameinLeftSidebar: string, + action?: string, + subActions: string, + ); + selectEntityByName(entityNameinLeftSidebar: string); + EvaluatFieldValue(fieldName?: string, currentValue?: string); + renameWithInPane(renameVal: string); + getEntityName(); + VerifyErrorMsgAbsence(errorMsgToVerifyAbsence: string); + VerifyErrorMsgPresence(errorMsgToVerifyAbsence: string); + setQueryTimeout(timeout: string); + VerifyNoDataDisplayAbsence(); + isNotInViewport(element: string); + isInViewport(element: string); + CheckAndUnfoldEntityItem(item: string); + DeleteEntityStateLocalStorage(); + checkLabelForWidget(options: string); + saveLocalStorageCache(); + restoreLocalStorageCache(); + StopContainer(path: string, containerName: string); + StopAllContainer(path: string); + StartContainer(path: string, containerName: string); + StartNewContainer( + url: string, + path: string, + version: string, + containerName: string, + ); + GetPath(path: string, containerName: string); + GetCWD(path: string); + GetAndVerifyLogs(path: string, containerName: string); + typeTab(); + CreatePage(); + GenerateCRUD(); + AddPageFromTemplate(); + verifyCallCount(alias: string, expectedNumberOfCalls: number); + RenameWidgetFromPropertyPane( + widgetType: string, + oldName: string, + newName: string, + ); + forceVisit(url: string); + SelectDropDown(dropdownOption: string); + RemoveMultiSelectItems(dropdownOptions: string[]); + RemoveAllSelections(); + SelectFromMultiSelect(options: string); + skipSignposting(); + stubPricingPage(); + validateEvaluatedValue(value: string); + } +} From 2670128bce4af51c7ed93f7e4271398541cf6205 Mon Sep 17 00:00:00 2001 From: Nidhi Date: Tue, 12 Mar 2024 23:21:44 +0530 Subject: [PATCH 13/25] chore: Split changes for mi dr values (#31677) Co-authored-by: Shrikant Sharat Kandula --- .../base/ActionCollectionServiceCE.java | 4 + .../base/ActionCollectionServiceCEImpl.java | 74 ++++++++++--- .../base/ActionCollectionServiceImpl.java | 14 ++- ...tionCollectionImportableServiceCEImpl.java | 25 +++-- ...ActionCollectionImportableServiceImpl.java | 4 +- ...ionApplicationImportableServiceCEImpl.java | 2 +- .../newactions/base/NewActionServiceCE.java | 2 +- .../base/NewActionServiceCEImpl.java | 10 +- .../NewActionImportableServiceCEImpl.java | 9 +- ...ionApplicationImportableServiceCEImpl.java | 2 +- .../JsActionRefactoringServiceCEImpl.java | 2 +- .../NewActionRefactoringServiceCEImpl.java | 2 +- ...ustomActionCollectionRepositoryCEImpl.java | 24 ++++- .../ce/CustomNewActionRepositoryCE.java | 2 +- .../ce/CustomNewActionRepositoryCEImpl.java | 15 ++- .../ce/LayoutActionServiceCEImpl.java | 11 +- .../ce/LayoutCollectionServiceCEImpl.java | 2 + .../ce/ActionExecutionSolutionCEImpl.java | 5 +- .../ActionCollectionServiceImplTest.java | 14 ++- .../services/CurlImporterServiceTest.java | 2 +- .../services/ce/ActionServiceCE_Test.java | 2 +- .../ce/ActionExecutionSolutionCEImplTest.java | 102 +++++++++--------- 22 files changed, 224 insertions(+), 105 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java index ea02ff2083..61a9de6e9e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java @@ -82,5 +82,9 @@ public interface ActionCollectionServiceCE extends CrudService generateActionCollectionViewDTO(ActionCollection actionCollection); + Mono bulkValidateAndInsertActionCollectionInRepository(List actionCollectionList); + + Mono bulkValidateAndUpdateActionCollectionInRepository(List actionCollectionList); + Mono saveLastEditInformationInParent(ActionCollectionDTO actionCollectionDTO); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java index 9bbdb68bc4..48542fa1b2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java @@ -17,7 +17,6 @@ import com.appsmith.server.dtos.ActionCollectionDTO; import com.appsmith.server.dtos.ActionCollectionViewDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; -import com.appsmith.server.helpers.DefaultResourcesUtils; import com.appsmith.server.helpers.ResponseUtils; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.repositories.ActionCollectionRepository; @@ -63,6 +62,9 @@ public class ActionCollectionServiceCEImpl extends BaseService defaultResourcesService; + private final DefaultResourcesService dtoDefaultResourcesService; + private final DefaultResourcesService newActionDefaultResourcesService; + private final DefaultResourcesService actionDTODefaultResourcesService; @Autowired public ActionCollectionServiceCEImpl( @@ -75,7 +77,10 @@ public class ActionCollectionServiceCEImpl extends BaseService defaultResourcesService) { + DefaultResourcesService defaultResourcesService, + DefaultResourcesService dtoDefaultResourcesService, + DefaultResourcesService newActionDefaultResourcesService, + DefaultResourcesService actionDTODefaultResourcesService) { super(validator, repository, analyticsService); this.newActionService = newActionService; @@ -85,6 +90,9 @@ public class ActionCollectionServiceCEImpl extends BaseService sendAnalyticsMono = analyticsService.sendCreateEvent(newAction, newActionService.getAnalyticsProperties(newAction)); @@ -705,20 +719,9 @@ public class ActionCollectionServiceCEImpl extends BaseService validateAndSaveCollection(ActionCollection actionCollection) { ActionCollectionDTO collectionDTO = actionCollection.getUnpublishedCollection(); - final Set validationMessages = collectionDTO.validate(); - if (!validationMessages.isEmpty()) { - return Mono.error(new AppsmithException( - AppsmithError.INVALID_ACTION_COLLECTION, collectionDTO.getName(), validationMessages.toString())); - } - DefaultResources defaultResources = collectionDTO.getDefaultResources(); - - if (defaultResources == null) { - DefaultResourcesUtils.createDefaultIdsOrUpdateWithGivenResourceIds(collectionDTO, null); - actionCollection.setDefaultResources(collectionDTO.getDefaultResources()); - } - - return Mono.justOrEmpty(collectionDTO.getActions()) + return validateActionCollection(actionCollection) + .thenReturn(collectionDTO.getActions()) .defaultIfEmpty(List.of()) .flatMapMany(Flux::fromIterable) .flatMap(action -> { @@ -777,6 +780,45 @@ public class ActionCollectionServiceCEImpl extends BaseService validateActionCollection(ActionCollection actionCollection) { + ActionCollectionDTO collectionDTO = actionCollection.getUnpublishedCollection(); + + collectionDTO.populateTransientFields(actionCollection); + + final Set validationMessages = collectionDTO.validate(); + if (!validationMessages.isEmpty()) { + return Mono.error(new AppsmithException( + AppsmithError.INVALID_ACTION_COLLECTION, collectionDTO.getName(), validationMessages.toString())); + } + + String branchName = null; + + if (actionCollection.getDefaultResources() != null) { + branchName = actionCollection.getDefaultResources().getBranchName(); + } + + defaultResourcesService.initialize(actionCollection, branchName, false); + dtoDefaultResourcesService.initialize(collectionDTO, branchName, false); + + return Mono.just(actionCollection); + } + + @Override + public Mono bulkValidateAndInsertActionCollectionInRepository(List actionCollectionList) { + return Flux.fromIterable(actionCollectionList) + .flatMap(this::validateActionCollection) + .collectList() + .flatMap(repository::bulkInsert); + } + + @Override + public Mono bulkValidateAndUpdateActionCollectionInRepository(List actionCollectionList) { + return Flux.fromIterable(actionCollectionList) + .flatMap(this::validateActionCollection) + .collectList() + .flatMap(repository::bulkUpdate); + } + protected void populateDefaultResources( ActionCollection actionCollection, ActionCollectionDTO collectionDTO, List actions) { // Store the default resource ids diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceImpl.java index d4a2521d12..c0bbe886c3 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceImpl.java @@ -1,9 +1,12 @@ package com.appsmith.server.actioncollections.base; +import com.appsmith.external.models.ActionDTO; import com.appsmith.server.acl.PolicyGenerator; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.defaultresources.DefaultResourcesService; import com.appsmith.server.domains.ActionCollection; +import com.appsmith.server.domains.NewAction; +import com.appsmith.server.dtos.ActionCollectionDTO; import com.appsmith.server.helpers.ResponseUtils; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.repositories.ActionCollectionRepository; @@ -17,7 +20,6 @@ import org.springframework.stereotype.Service; @Service @Slf4j public class ActionCollectionServiceImpl extends ActionCollectionServiceCEImpl implements ActionCollectionService { - public ActionCollectionServiceImpl( Validator validator, ActionCollectionRepository repository, @@ -28,7 +30,10 @@ public class ActionCollectionServiceImpl extends ActionCollectionServiceCEImpl i ResponseUtils responseUtils, ApplicationPermission applicationPermission, ActionPermission actionPermission, - DefaultResourcesService defaultResourcesService) { + DefaultResourcesService defaultResourcesService, + DefaultResourcesService dtoDefaultResourcesService, + DefaultResourcesService newActionDefaultResourcesService, + DefaultResourcesService actionDTODefaultResourcesService) { super( validator, repository, @@ -39,6 +44,9 @@ public class ActionCollectionServiceImpl extends ActionCollectionServiceCEImpl i responseUtils, applicationPermission, actionPermission, - defaultResourcesService); + defaultResourcesService, + dtoDefaultResourcesService, + newActionDefaultResourcesService, + actionDTODefaultResourcesService); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java index 953e67c608..63bd3710d0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java @@ -1,6 +1,7 @@ package com.appsmith.server.actioncollections.importable; import com.appsmith.external.models.Policy; +import com.appsmith.server.actioncollections.base.ActionCollectionService; import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Artifact; @@ -33,6 +34,8 @@ import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullP @Service @RequiredArgsConstructor public class ActionCollectionImportableServiceCEImpl implements ImportableServiceCE { + + private final ActionCollectionService actionCollectionService; private final ActionCollectionRepository repository; protected final ArtifactBasedImportableService applicationImportableService; @@ -238,9 +241,13 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic "Saving action collections in bulk. New: {}, Updated: {}", newActionCollections.size(), existingActionCollections.size()); - return repository - .bulkInsert(newActionCollections) - .then(repository.bulkUpdate(existingActionCollections)) + return Mono.when( + actionCollectionService + .bulkValidateAndInsertActionCollectionInRepository( + newActionCollections), + actionCollectionService + .bulkValidateAndUpdateActionCollectionInRepository( + existingActionCollections)) .thenReturn(resultDTO); }); }) @@ -257,7 +264,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic ActionCollection branchedActionCollection, ActionCollection actionCollection) { - ArtifactBasedImportableService artifactBasedExportableService = + ArtifactBasedImportableService artifactBasedImportableService = this.getArtifactBasedImportableService(importingMetaDTO); String idFromJsonFile = actionCollection.getId(); @@ -277,7 +284,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic unpublishedCollection.setPluginId( mappedImportableResourcesDTO.getPluginMap().get(unpublishedCollection.getPluginId())); - parentContext = artifactBasedExportableService.updateContextInResource( + parentContext = artifactBasedImportableService.updateContextInResource( unpublishedCollection, mappedImportableResourcesDTO.getContextMap(), fallbackDefaultContextId); } @@ -289,7 +296,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic publishedCollection.setPluginId( mappedImportableResourcesDTO.getPluginMap().get(publishedCollection.getPluginId())); - Context publishedCollectionContext = artifactBasedExportableService.updateContextInResource( + Context publishedCollectionContext = artifactBasedImportableService.updateContextInResource( publishedCollection, mappedImportableResourcesDTO.getContextMap(), fallbackDefaultContextId); parentContext = parentContext == null ? publishedCollectionContext : parentContext; } @@ -297,7 +304,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic actionCollection.makePristine(); actionCollection.setWorkspaceId(workspaceId); - artifactBasedExportableService.populateDefaultResources( + artifactBasedImportableService.populateDefaultResources( importingMetaDTO, mappedImportableResourcesDTO, artifact, branchedActionCollection, actionCollection); return parentContext; } @@ -369,9 +376,9 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic protected ActionCollection getExistingCollectionInOtherBranchesForImportedCollection( MappedImportableResourcesDTO mappedImportableResourcesDTO, - Map actionsCollectionsInCurrentArtifact, + Map actionsCollectionsInOtherArtifact, ActionCollection actionCollection) { - return actionsCollectionsInCurrentArtifact.get(actionCollection.getGitSyncId()); + return actionsCollectionsInOtherArtifact.get(actionCollection.getGitSyncId()); } protected boolean existingArtifactContainsCollection( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceImpl.java index 64cd61563b..52cd9c61a9 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceImpl.java @@ -1,5 +1,6 @@ package com.appsmith.server.actioncollections.importable; +import com.appsmith.server.actioncollections.base.ActionCollectionService; import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.Application; import com.appsmith.server.imports.importable.ImportableService; @@ -12,8 +13,9 @@ public class ActionCollectionImportableServiceImpl extends ActionCollectionImpor implements ImportableService { public ActionCollectionImportableServiceImpl( + ActionCollectionService actionCollectionService, ActionCollectionRepository repository, ArtifactBasedImportableService applicationImportableService) { - super(repository, applicationImportableService); + super(actionCollectionService, repository, applicationImportableService); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java index cb98965e33..cf77ea8f7f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java @@ -58,7 +58,7 @@ public class ActionCollectionApplicationImportableServiceCEImpl @Override public Flux getExistingResourcesInCurrentArtifactFlux(Artifact artifact) { - return repository.findByApplicationId(artifact.getId()); + return repository.findByApplicationId(artifact.getId(), Optional.empty(), Optional.empty()); } @Override diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java index 5c90365906..768a422a41 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java @@ -122,7 +122,7 @@ public interface NewActionServiceCE extends CrudService { Flux getUnpublishedActionsExceptJs(MultiValueMap params, String branchName); Mono findByBranchNameAndDefaultActionId( - String branchName, String defaultActionId, AclPermission permission); + String branchName, String defaultActionId, Boolean viewMode, AclPermission permission); Mono findBranchedIdByBranchNameAndDefaultActionId( String branchName, String defaultActionId, AclPermission permission); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java index 82af61e43f..df9ac0dbde 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java @@ -212,7 +212,7 @@ public class NewActionServiceCEImpl extends BaseService findByIdAndBranchName(String id, String branchName) { - return this.findByBranchNameAndDefaultActionId(branchName, id, actionPermission.getReadPermission()) + return this.findByBranchNameAndDefaultActionId(branchName, id, false, actionPermission.getReadPermission()) .map(responseUtils::updateNewActionWithDefaultResources); } @@ -1473,7 +1473,7 @@ public class NewActionServiceCEImpl extends BaseService archiveByIdAndBranchName(String id, String branchName) { Mono branchedActionMono = - this.findByBranchNameAndDefaultActionId(branchName, id, actionPermission.getDeletePermission()); + this.findByBranchNameAndDefaultActionId(branchName, id, false, actionPermission.getDeletePermission()); return branchedActionMono .flatMap(branchedAction -> this.archiveById(branchedAction.getId())) @@ -1560,7 +1560,7 @@ public class NewActionServiceCEImpl extends BaseService findByBranchNameAndDefaultActionId( - String branchName, String defaultActionId, AclPermission permission) { + String branchName, String defaultActionId, Boolean viewMode, AclPermission permission) { log.debug("Going to find action based on branchName and defaultActionId with id: {} ", defaultActionId); if (!StringUtils.hasLength(branchName)) { return repository @@ -1569,7 +1569,7 @@ public class NewActionServiceCEImpl extends BaseService actionsInOtherArtifact, + NewAction newAction) { + return actionsInOtherArtifact.get(newAction.getGitSyncId()); + } + protected boolean existingArtifactContainsAction( Map actionsInCurrentArtifact, NewAction newAction) { return newAction.getGitSyncId() != null && actionsInCurrentArtifact.containsKey(newAction.getGitSyncId()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java index 071914873a..030ab4ab56 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java @@ -58,7 +58,7 @@ public class NewActionApplicationImportableServiceCEImpl @Override public Flux getExistingResourcesInCurrentArtifactFlux(Artifact artifact) { - return repository.findByApplicationId(artifact.getId()); + return repository.findByApplicationId(artifact.getId(), Optional.empty(), Optional.empty()); } @Override diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/JsActionRefactoringServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/JsActionRefactoringServiceCEImpl.java index 2d6f530eda..54141556a9 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/JsActionRefactoringServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/JsActionRefactoringServiceCEImpl.java @@ -56,7 +56,7 @@ public class JsActionRefactoringServiceCEImpl implements EntityRefactoringServic // Fetch branched action as client only knows about the default action IDs Mono branchedActionMono = newActionService .findByBranchNameAndDefaultActionId( - branchName, refactorEntityNameDTO.getActionId(), actionPermission.getEditPermission()) + branchName, refactorEntityNameDTO.getActionId(), false, actionPermission.getEditPermission()) .map(branchedAction -> { refactorEntityNameDTO.setActionId(branchedAction.getId()); defaultActionCollection.setPageId( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/NewActionRefactoringServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/NewActionRefactoringServiceCEImpl.java index 61769ba9bb..71d7f245a1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/NewActionRefactoringServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/refactors/NewActionRefactoringServiceCEImpl.java @@ -127,7 +127,7 @@ public class NewActionRefactoringServiceCEImpl implements EntityRefactoringServi public Mono updateRefactoredEntity(RefactorEntityNameDTO refactorEntityNameDTO, String branchName) { return newActionService .findByBranchNameAndDefaultActionId( - branchName, refactorEntityNameDTO.getActionId(), actionPermission.getEditPermission()) + branchName, refactorEntityNameDTO.getActionId(), false, actionPermission.getEditPermission()) .map(branchedAction -> newActionService.generateActionByViewMode(branchedAction, false)) .flatMap(action -> { action.setName(refactorEntityNameDTO.getNewName()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java index f20a19ac73..8a32e9e174 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java @@ -51,11 +51,17 @@ public class CustomActionCollectionRepositoryCEImpl extends BaseAppsmithReposito public Flux findByApplicationId( String applicationId, Optional aclPermission, Optional sort) { - Criteria applicationCriteria = - where(ActionCollection.Fields.applicationId).is(applicationId); + List criteria = new ArrayList<>(); + + Criteria applicationCriteria = Criteria.where(FieldName.APPLICATION_ID).is(applicationId); + criteria.add(applicationCriteria); + + Criteria deletedCriteria = + where(ActionCollection.Fields.unpublishedCollection_deletedAt).is(null); + criteria.add(deletedCriteria); return queryBuilder() - .criteria(applicationCriteria) + .criteria(criteria) .permission(aclPermission.orElse(null)) .sort(sort.orElse(null)) .all(); @@ -219,11 +225,19 @@ public class CustomActionCollectionRepositoryCEImpl extends BaseAppsmithReposito @Override public Flux findByDefaultApplicationId( String defaultApplicationId, Optional permission) { + List criteria = new ArrayList<>(); + final String defaultResources = BranchAwareDomain.Fields.defaultResources; Criteria defaultAppIdCriteria = where(defaultResources + "." + FieldName.APPLICATION_ID).is(defaultApplicationId); + criteria.add(defaultAppIdCriteria); + + Criteria deletedCriteria = + where(ActionCollection.Fields.unpublishedCollection_deletedAt).is(null); + criteria.add(deletedCriteria); + return queryBuilder() - .criteria(defaultAppIdCriteria) + .criteria(criteria) .permission(permission.orElse(null)) .all(); } @@ -247,7 +261,9 @@ public class CustomActionCollectionRepositoryCEImpl extends BaseAppsmithReposito @Override public Flux findAllByApplicationIds(List applicationIds, List includeFields) { + Criteria applicationCriteria = Criteria.where(FieldName.APPLICATION_ID).in(applicationIds); + return queryBuilder() .criteria(applicationCriteria) .fields(includeFields) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java index 33965df367..b111d8b0e4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java @@ -45,7 +45,7 @@ public interface CustomNewActionRepositoryCE extends AppsmithRepository countByDatasourceId(String datasourceId); Mono findByBranchNameAndDefaultActionId( - String branchName, String defaultActionId, AclPermission permission); + String branchName, String defaultActionId, Boolean viewMode, AclPermission permission); Flux findByDefaultApplicationId(String defaultApplicationId, Optional permission); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java index d722a4e7c2..0fc034da77 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java @@ -61,7 +61,8 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl< public Flux findByApplicationId( String applicationId, Optional aclPermission, Optional sort) { return queryBuilder() - .criteria(getCriterionForFindByApplicationId(applicationId)) + .criteria(getCriterionForFindByApplicationId(applicationId) + .isNull(NewAction.Fields.unpublishedAction_deletedAt)) .permission(aclPermission.orElse(null)) .sort(sort.orElse(null)) .all(); @@ -238,11 +239,18 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl< @Override public Mono findByBranchNameAndDefaultActionId( - String branchName, String defaultActionId, AclPermission permission) { + String branchName, String defaultActionId, Boolean viewMode, AclPermission permission) { final String defaultResources = NewAction.Fields.defaultResources; final BridgeQuery q = Bridge.equal( defaultResources + "." + FieldName.ACTION_ID, defaultActionId) .equal(defaultResources + "." + FieldName.BRANCH_NAME, branchName); + + if (Boolean.FALSE.equals(viewMode)) { + // In case an action has been deleted in edit mode, but still exists in deployed mode, NewAction object + // would exist. To handle this, only fetch non-deleted actions + q.isNull(NewAction.Fields.unpublishedAction_deletedAt); + } + return queryBuilder().criteria(q).permission(permission).one(); } @@ -332,7 +340,8 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl< public Flux findByDefaultApplicationId(String defaultApplicationId, Optional permission) { final String defaultResources = BranchAwareDomain.Fields.defaultResources; return queryBuilder() - .criteria(Bridge.equal(defaultResources + "." + FieldName.APPLICATION_ID, defaultApplicationId)) + .criteria(Bridge.equal(defaultResources + "." + FieldName.APPLICATION_ID, defaultApplicationId) + .isNull(NewAction.Fields.unpublishedAction_deletedAt)) .permission(permission.orElse(null)) .all(); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java index 5adf5548b1..76edaec336 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java @@ -211,7 +211,7 @@ public class LayoutActionServiceCEImpl implements LayoutActionServiceCE { .map(NewPage::getId); Mono branchedActionMono = newActionService.findByBranchNameAndDefaultActionId( - branchName, actionMoveDTO.getAction().getId(), actionPermission.getEditPermission()); + branchName, actionMoveDTO.getAction().getId(), false, actionPermission.getEditPermission()); return Mono.zip(toPageMono, branchedActionMono) .flatMap(tuple -> { @@ -253,7 +253,8 @@ public class LayoutActionServiceCEImpl implements LayoutActionServiceCE { public Mono updateSingleActionWithBranchName( String defaultActionId, ActionDTO action, String branchName) { return newActionService - .findByBranchNameAndDefaultActionId(branchName, defaultActionId, actionPermission.getEditPermission()) + .findByBranchNameAndDefaultActionId( + branchName, defaultActionId, false, actionPermission.getEditPermission()) .flatMap(newAction -> updateActionBasedOnContextType(newAction, action)); } @@ -308,7 +309,8 @@ public class LayoutActionServiceCEImpl implements LayoutActionServiceCE { @Override public Mono setExecuteOnLoad(String defaultActionId, String branchName, Boolean isExecuteOnLoad) { return newActionService - .findByBranchNameAndDefaultActionId(branchName, defaultActionId, actionPermission.getEditPermission()) + .findByBranchNameAndDefaultActionId( + branchName, defaultActionId, false, actionPermission.getEditPermission()) .flatMap(branchedAction -> setExecuteOnLoad(branchedAction.getId(), isExecuteOnLoad)) .map(responseUtils::updateActionDTOWithDefaultResources); } @@ -330,7 +332,8 @@ public class LayoutActionServiceCEImpl implements LayoutActionServiceCE { public Mono deleteUnpublishedAction(String defaultActionId, String branchName) { return newActionService - .findByBranchNameAndDefaultActionId(branchName, defaultActionId, actionPermission.getDeletePermission()) + .findByBranchNameAndDefaultActionId( + branchName, defaultActionId, false, actionPermission.getDeletePermission()) .flatMap(branchedAction -> deleteUnpublishedAction(branchedAction.getId())) .map(responseUtils::updateActionDTOWithDefaultResources) .flatMap(actionDTO -> newActionService diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java index 7b41ca62f2..8e35bf332f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java @@ -382,6 +382,7 @@ public class LayoutCollectionServiceCEImpl implements LayoutCollectionServiceCE .findByBranchNameAndDefaultActionId( branchName, actionDTO.getId(), + false, actionPermission.getEditPermission()) .map(NewAction::getId); actionDTO.setId(null); @@ -432,6 +433,7 @@ public class LayoutCollectionServiceCEImpl implements LayoutCollectionServiceCE .findByBranchNameAndDefaultActionId( branchName, actionDTO.getId(), + false, actionPermission.getEditPermission()) .map(NewAction::getId); actionDTO.setId(null); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java index 450f1ac463..8ff75a901b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImpl.java @@ -190,7 +190,10 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE AclPermission executePermission = getPermission(executeActionMetaDTO, actionPermission.getExecutePermission()); Mono newActionMono = newActionService .findByBranchNameAndDefaultActionId( - executeActionMetaDTO.getBranchName(), executeActionDTO.getActionId(), executePermission) + executeActionMetaDTO.getBranchName(), + executeActionDTO.getActionId(), + executeActionDTO.getViewMode(), + executePermission) .cache(); Mono populatedExecuteActionDTOMono = diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java index e548b95eaf..97d4f5fcca 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java @@ -125,6 +125,15 @@ public class ActionCollectionServiceImplTest { @MockBean private DefaultResourcesService actionCollectionDefaultResourcesService; + @MockBean + private DefaultResourcesService actionCollectionDtoDefaultResourcesService; + + @MockBean + private DefaultResourcesService newActionDefaultResourcesService; + + @MockBean + private DefaultResourcesService actionDTODefaultResourcesService; + @BeforeEach public void setUp() { applicationPermission = new ApplicationPermissionImpl(); @@ -140,7 +149,10 @@ public class ActionCollectionServiceImplTest { responseUtils, applicationPermission, actionPermission, - actionCollectionDefaultResourcesService); + actionCollectionDefaultResourcesService, + actionCollectionDtoDefaultResourcesService, + newActionDefaultResourcesService, + actionDTODefaultResourcesService); layoutCollectionService = new LayoutCollectionServiceImpl( newPageService, diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java index 41ad9260e8..54ba24f855 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java @@ -482,7 +482,7 @@ public class CurlImporterServiceTest { // fetch branched action Mono branchedSavedActionMono = branchedResultMono.flatMap(actionDTO -> newActionService.findByBranchNameAndDefaultActionId( - "testBranch", actionDTO.getId(), AclPermission.MANAGE_ACTIONS)); + "testBranch", actionDTO.getId(), false, AclPermission.MANAGE_ACTIONS)); StepVerifier.create(Mono.zip(branchedResultMono, branchedPageMono, branchedSavedActionMono)) .assertNext(tuple -> { diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java index ea63f3af68..b840d25b85 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java @@ -315,7 +315,7 @@ public class ActionServiceCE_Test { Mono actionMono = layoutActionService .createSingleActionWithBranch(action, branchName) .flatMap(createdAction -> newActionService.findByBranchNameAndDefaultActionId( - branchName, createdAction.getId(), READ_ACTIONS)); + branchName, createdAction.getId(), false, READ_ACTIONS)); StepVerifier.create(actionMono) .assertNext(newAction -> { diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImplTest.java index 509520214c..8aaac8bc4c 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCEImplTest.java @@ -264,20 +264,20 @@ class ActionExecutionSolutionCEImplTest { public void testExecuteAPIWithUsualOrderingOfTheParts() { String usualOrderOfParts = """ - --boundary\r - Content-Disposition: form-data; name="executeActionDTO"\r - \r - {"actionId":"63285a3388e48972c7519b18","viewMode":false,"paramProperties":{"k0":{"datatype": "string"}}}\r - --boundary\r - Content-Disposition: form-data; name="parameterMap"\r - \r - {"Input1.text":"k0"}\r - --boundary\r - Content-Disposition: form-data; name="k0"; filename="blob"\r - Content-Type: text/plain\r - \r - xyz\r - --boundary--"""; + --boundary\r + Content-Disposition: form-data; name="executeActionDTO"\r + \r + {"actionId":"63285a3388e48972c7519b18","viewMode":false,"paramProperties":{"k0":{"datatype": "string"}}}\r + --boundary\r + Content-Disposition: form-data; name="parameterMap"\r + \r + {"Input1.text":"k0"}\r + --boundary\r + Content-Disposition: form-data; name="k0"; filename="blob"\r + Content-Type: text/plain\r + \r + xyz\r + --boundary--"""; MockServerHttpRequest mock = MockServerHttpRequest.method(HttpMethod.POST, URI.create("https://example.com")) .contentType(new MediaType("multipart", "form-data", Map.of("boundary", "boundary"))) @@ -306,7 +306,9 @@ class ActionExecutionSolutionCEImplTest { .getTrueEnvironmentId( any(), any(), any(), Mockito.eq(environmentPermission.getExecutePermission()), anyBoolean()); doReturn(Mono.just(mockResult)).when(executionSolutionSpy).executeAction(any(), any()); - doReturn(Mono.just(newAction)).when(newActionService).findByBranchNameAndDefaultActionId(any(), any(), any()); + doReturn(Mono.just(newAction)) + .when(newActionService) + .findByBranchNameAndDefaultActionId(any(), any(), Mockito.anyBoolean(), any()); StepVerifier.create(actionExecutionResultMono) .assertNext(response -> { @@ -322,20 +324,20 @@ class ActionExecutionSolutionCEImplTest { public void testExecuteAPIWithParameterMapAsLastPart() { String parameterMapAtLast = """ - --boundary\r - Content-Disposition: form-data; name="executeActionDTO"\r - \r - {"actionId":"63285a3388e48972c7519b18","viewMode":false,"paramProperties":{"k0":{"datatype": "string"}}}\r - --boundary\r - Content-Disposition: form-data; name="k0"; filename="blob"\r - Content-Type: text/plain\r - \r - xyz\r - --boundary\r - Content-Disposition: form-data; name="parameterMap"\r - \r - {"Input1.text":"k0"}\r - --boundary--"""; + --boundary\r + Content-Disposition: form-data; name="executeActionDTO"\r + \r + {"actionId":"63285a3388e48972c7519b18","viewMode":false,"paramProperties":{"k0":{"datatype": "string"}}}\r + --boundary\r + Content-Disposition: form-data; name="k0"; filename="blob"\r + Content-Type: text/plain\r + \r + xyz\r + --boundary\r + Content-Disposition: form-data; name="parameterMap"\r + \r + {"Input1.text":"k0"}\r + --boundary--"""; MockServerHttpRequest mock = MockServerHttpRequest.method(HttpMethod.POST, URI.create("https://example.com")) .contentType(new MediaType("multipart", "form-data", Map.of("boundary", "boundary"))) @@ -364,7 +366,9 @@ class ActionExecutionSolutionCEImplTest { .getTrueEnvironmentId( any(), any(), any(), Mockito.eq(environmentPermission.getExecutePermission()), anyBoolean()); doReturn(Mono.just(mockResult)).when(executionSolutionSpy).executeAction(any(), any()); - doReturn(Mono.just(newAction)).when(newActionService).findByBranchNameAndDefaultActionId(any(), any(), any()); + doReturn(Mono.just(newAction)) + .when(newActionService) + .findByBranchNameAndDefaultActionId(any(), any(), Mockito.anyBoolean(), any()); StepVerifier.create(actionExecutionResultMono) .assertNext(response -> { @@ -380,25 +384,25 @@ class ActionExecutionSolutionCEImplTest { public void testParsePartsAndGetParamsFlux_withBlobIdentifiers_replacesValueInParam() { String partsWithBlobRefs = """ - --boundary\r - Content-Disposition: form-data; name="executeActionDTO"\r - \r - {"actionId":"63285a3388e48972c7519b18","viewMode":false,"paramProperties":{"k0":{"datatype": "string", "blobIdentifiers": ["blob:12345678-1234-1234-1234-123456781234"]}}}\r - --boundary\r - Content-Disposition: form-data; name="parameterMap"\r - \r - {"Input1.text":"k0"}\r - --boundary\r - Content-Disposition: form-data; name="k0"; filename="blob"\r - Content-Type: text/plain\r - \r - {"name": "randomName", "data": "blob:12345678-1234-1234-1234-123456781234"}\r - --boundary\r - Content-Disposition: form-data; name="blob:12345678-1234-1234-1234-123456781234"; filename="blob"\r - Content-Type: text/plain\r - \r - xy\\nz\r - --boundary--"""; + --boundary\r + Content-Disposition: form-data; name="executeActionDTO"\r + \r + {"actionId":"63285a3388e48972c7519b18","viewMode":false,"paramProperties":{"k0":{"datatype": "string", "blobIdentifiers": ["blob:12345678-1234-1234-1234-123456781234"]}}}\r + --boundary\r + Content-Disposition: form-data; name="parameterMap"\r + \r + {"Input1.text":"k0"}\r + --boundary\r + Content-Disposition: form-data; name="k0"; filename="blob"\r + Content-Type: text/plain\r + \r + {"name": "randomName", "data": "blob:12345678-1234-1234-1234-123456781234"}\r + --boundary\r + Content-Disposition: form-data; name="blob:12345678-1234-1234-1234-123456781234"; filename="blob"\r + Content-Type: text/plain\r + \r + xy\\nz\r + --boundary--"""; MockServerHttpRequest mock = MockServerHttpRequest.method(HttpMethod.POST, URI.create("https://example.com")) .contentType(new MediaType("multipart", "form-data", Map.of("boundary", "boundary"))) From 2dd730bcc3f2746d4a0e2b4c4939841fcc085ba1 Mon Sep 17 00:00:00 2001 From: Nirmal Sarswat <25587962+vivonk@users.noreply.github.com> Date: Wed, 13 Mar 2024 00:53:53 +0530 Subject: [PATCH 14/25] fix: Handle error in trigger requests Appsmith AI (#31549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Handling unexpected errors in trigger requests in Appsmith AI plugin #### PR fixes following issue(s) Fixes # #### Type of change - Bug fix (non-breaking change which fixes an issue) #### How Has This Been Tested? - [x] Manual ## Automation /ok-to-test tags="@tag.Datasource" ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed ## Summary by CodeRabbit - **Bug Fixes** - Improved error handling for file uploading and listing to enhance stability and user experience. > [!IMPORTANT] > Workflow run: > Commit: `8a36d1b0216f86c18ebee541fbad2fec9e66dfb9` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 --- .../external/plugins/AppsmithAiPlugin.java | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java index 738784c0fe..2e4829a04d 100644 --- a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java +++ b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java @@ -87,7 +87,9 @@ public class AppsmithAiPlugin extends BasePlugin { TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); triggerResultDTO.setTrigger(response); return Mono.just(triggerResultDTO); - }); + }) + .onErrorResume( + error -> handleError("An error has occurred while trying to upload files", error)); } else if (LIST_FILES.equals(requestType)) { List fileIds = getFileIds(datasourceConfiguration); if (fileIds.isEmpty()) { @@ -101,27 +103,39 @@ public class AppsmithAiPlugin extends BasePlugin { "NO_FILES_AVAILABLE"))); return Mono.just(triggerResultDTO); } - return aiServerService.getFilesStatus(fileIds, sourceDetails).flatMap(fileStatusDTO -> { - List> response = new ArrayList<>(); - fileStatusDTO.getFiles().forEach(file -> { - Map dropdownOption = new HashMap<>(); - if (!file.isProcessed()) { - dropdownOption.put(LABEL, "(Processing...) " + file.getName()); - } else { - dropdownOption.put(LABEL, file.getName()); - } - dropdownOption.put(VALUE, file.getId()); - dropdownOption.put(DISABLED, !file.isProcessed()); - response.add(dropdownOption); - }); - TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); - triggerResultDTO.setTrigger(response); - return Mono.just(triggerResultDTO); - }); + return aiServerService + .getFilesStatus(fileIds, sourceDetails) + .flatMap(fileStatusDTO -> { + List> response = new ArrayList<>(); + fileStatusDTO.getFiles().forEach(file -> { + Map dropdownOption = new HashMap<>(); + if (!file.isProcessed()) { + dropdownOption.put(LABEL, "(Processing...) " + file.getName()); + } else { + dropdownOption.put(LABEL, file.getName()); + } + dropdownOption.put(VALUE, file.getId()); + dropdownOption.put(DISABLED, !file.isProcessed()); + response.add(dropdownOption); + }); + TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); + triggerResultDTO.setTrigger(response); + return Mono.just(triggerResultDTO); + }) + .onErrorResume(error -> + handleError("An error has occurred while trying to list uploaded files", error)); } return super.trigger(connection, datasourceConfiguration, request); } + private Mono handleError(String message, Throwable error) { + log.error("{}. Error: {}", message, error.getMessage()); + if (!(error instanceof AppsmithPluginException)) { + error = new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, error.getMessage(), error); + } + return Mono.error(error); + } + @Override public Mono executeParameterized( APIConnection connection, From f65d9d0eadde6cc83b04a0106b4f9385c2b93066 Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Wed, 13 Mar 2024 02:11:38 +0530 Subject: [PATCH 15/25] fix: added error handling for updateLayout failure while importing (#31694) --- .../ApplicationImportServiceCEImpl.java | 15 +- .../imports/internal/ImportServiceTests.java | 142 + .../server/imports/internal/faulty-dsl.json | 4713 +++++++++++++++++ 3 files changed, 4869 insertions(+), 1 deletion(-) create mode 100644 app/server/appsmith-server/src/test/resources/com/appsmith/server/imports/internal/faulty-dsl.json diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java index aaf6a38cc1..d8889bd077 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java @@ -22,6 +22,7 @@ import com.appsmith.server.dtos.MappedImportableResourcesDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.ImportArtifactPermissionProvider; +import com.appsmith.server.helpers.ImportExportUtils; import com.appsmith.server.imports.importable.ImportableService; import com.appsmith.server.imports.internal.artifactbased.ArtifactBasedImportServiceCE; import com.appsmith.server.layouts.UpdateLayoutService; @@ -484,7 +485,19 @@ public class ApplicationImportServiceCEImpl .flatMap(application -> { return Flux.fromIterable(application.getPages()) .map(ApplicationPage::getId) - .flatMap(updateLayoutService::updatePageLayoutsByPageId) + .flatMap(pageId -> { + return updateLayoutService + .updatePageLayoutsByPageId(pageId) + .onErrorResume(throwable -> { + // the error would most probably arise because of update layout error, + // this shouldn't stop the application from getting imported. + String errorMessage = ImportExportUtils.getErrorMessage(throwable); + log.error( + "Error while updating layout. Error: {}", errorMessage, throwable); + // continuing the execution + return Mono.just(""); + }); + }) .collectList() .thenReturn(application); }); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java index 4876dc8f3c..87710cda57 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java @@ -108,6 +108,9 @@ import reactor.test.StepVerifier; import reactor.util.function.Tuple3; import reactor.util.function.Tuple4; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; @@ -5191,4 +5194,143 @@ public class ImportServiceTests { }) .verifyComplete(); } + + @Test + @WithUserDetails(value = "api_user") + public void importApplication_WhenUpdateLayoutFailures_Success() throws URISyntaxException { + FilePart filePart = createFilePartWithIdenticalPackageStructure("faulty-dsl.json"); + + Workspace newWorkspace = new Workspace(); + newWorkspace.setName("Template Workspace"); + + Mono workspaceMono = workspaceService.create(newWorkspace).cache(); + + final Mono resultMono = workspaceMono + .flatMap(workspace -> + importService.extractArtifactExchangeJsonAndSaveArtifact(filePart, workspace.getId(), null)) + .map(importableArtifactDTO -> (ApplicationImportDTO) importableArtifactDTO); + + List permissionGroups = workspaceMono + .flatMapMany(savedWorkspace -> { + Set defaultPermissionGroups = savedWorkspace.getDefaultPermissionGroups(); + return permissionGroupRepository.findAllById(defaultPermissionGroups); + }) + .collectList() + .block(); + + PermissionGroup adminPermissionGroup = permissionGroups.stream() + .filter(permissionGroup -> permissionGroup.getName().startsWith(FieldName.ADMINISTRATOR)) + .findFirst() + .get(); + + PermissionGroup developerPermissionGroup = permissionGroups.stream() + .filter(permissionGroup -> permissionGroup.getName().startsWith(FieldName.DEVELOPER)) + .findFirst() + .get(); + + PermissionGroup viewerPermissionGroup = permissionGroups.stream() + .filter(permissionGroup -> permissionGroup.getName().startsWith(FieldName.VIEWER)) + .findFirst() + .get(); + + Policy manageAppPolicy = Policy.builder() + .permission(MANAGE_APPLICATIONS.getValue()) + .permissionGroups(Set.of(adminPermissionGroup.getId(), developerPermissionGroup.getId())) + .build(); + Policy readAppPolicy = Policy.builder() + .permission(READ_APPLICATIONS.getValue()) + .permissionGroups(Set.of( + adminPermissionGroup.getId(), developerPermissionGroup.getId(), viewerPermissionGroup.getId())) + .build(); + + StepVerifier.create(resultMono.flatMap(applicationImportDTO -> { + Application application = applicationImportDTO.getApplication(); + return Mono.zip( + Mono.just(applicationImportDTO), + datasourceService + .getAllByWorkspaceIdWithStorages( + application.getWorkspaceId(), Optional.of(MANAGE_DATASOURCES)) + .collectList(), + newActionService + .findAllByApplicationIdAndViewMode(application.getId(), false, READ_ACTIONS, null) + .collectList(), + newPageService + .findByApplicationId(application.getId(), MANAGE_PAGES, false) + .collectList(), + actionCollectionService + .findAllByApplicationIdAndViewMode(application.getId(), false, MANAGE_ACTIONS, null) + .collectList()); + })) + .assertNext(tuple -> { + final Application application = tuple.getT1().getApplication(); + final List unConfiguredDatasourceList = + tuple.getT1().getUnConfiguredDatasourceList(); + final boolean isPartialImport = tuple.getT1().getIsPartialImport(); + final List datasourceList = tuple.getT2(); + final List actionList = tuple.getT3(); + final List pageList = tuple.getT4(); + final List actionCollectionList = tuple.getT5(); + + assertThat(application.getName()).isEqualTo("faultDSL"); + assertThat(application.getWorkspaceId()).isNotNull(); + assertThat(application.getPages()).hasSize(1); + assertThat(application.getPolicies()).containsAll(Set.of(manageAppPolicy, readAppPolicy)); + assertThat(application.getPublishedPages()).hasSize(0); + assertThat(application.getModifiedBy()).isEqualTo("api_user"); + assertThat(application.getUpdatedAt()).isNotNull(); + assertThat(application.getEditModeThemeId()).isNotNull(); + assertThat(application.getPublishedModeThemeId()).isNotNull(); + assertThat(isPartialImport).isEqualTo(Boolean.TRUE); + assertThat(unConfiguredDatasourceList.size()).isNotEqualTo(0); + + assertThat(datasourceList).isNotEmpty(); + List datasourceNames = unConfiguredDatasourceList.stream() + .map(Datasource::getName) + .collect(Collectors.toList()); + assertThat(datasourceNames).contains("Mock_DB"); + + List collectionIdInAction = new ArrayList<>(); + assertThat(actionList).isNotEmpty(); + actionList.forEach(newAction -> { + ActionDTO actionDTO = newAction.getUnpublishedAction(); + assertThat(actionDTO.getPageId()) + .isNotEqualTo(pageList.get(0).getName()); + if (!StringUtils.isEmpty(actionDTO.getCollectionId())) { + collectionIdInAction.add(actionDTO.getCollectionId()); + } + }); + + assertThat(actionCollectionList).isNotEmpty(); + assertThat(actionCollectionList).hasSize(1); + assertThat(pageList).hasSize(1); + + ApplicationPage defaultAppPage = application.getPages().stream() + .filter(ApplicationPage::getIsDefault) + .findFirst() + .orElse(null); + assertThat(defaultAppPage).isNotNull(); + + PageDTO defaultPageDTO = pageList.stream() + .filter(pageDTO -> pageDTO.getId().equals(defaultAppPage.getId())) + .findFirst() + .orElse(null); + + assertThat(defaultPageDTO).isNotNull(); + }) + .verifyComplete(); + } + + // this would be the newer way to create the fileParts + private FilePart createFilePartWithIdenticalPackageStructure(String filePath) throws URISyntaxException { + FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS); + URL resource = this.getClass().getResource(filePath); + Flux dataBufferFlux = DataBufferUtils.read( + Path.of(resource.toURI()), new DefaultDataBufferFactory(), 4096) + .cache(); + + Mockito.when(filepart.content()).thenReturn(dataBufferFlux); + Mockito.when(filepart.headers().getContentType()).thenReturn(MediaType.APPLICATION_JSON); + + return filepart; + } } diff --git a/app/server/appsmith-server/src/test/resources/com/appsmith/server/imports/internal/faulty-dsl.json b/app/server/appsmith-server/src/test/resources/com/appsmith/server/imports/internal/faulty-dsl.json new file mode 100644 index 0000000000..68f2e5e599 --- /dev/null +++ b/app/server/appsmith-server/src/test/resources/com/appsmith/server/imports/internal/faulty-dsl.json @@ -0,0 +1,4713 @@ +{ + "artifactJsonType": "APPLICATION", + "clientSchemaVersion": 1.0, + "serverSchemaVersion": 7.0, + "exportedApplication": { + "name": "faultDSL", + "isPublic": false, + "pages": [{ "id": "Admin", "isDefault": true }], + "publishedPages": [{ "isDefault": true }], + "viewMode": false, + "appIsExample": false, + "unreadCommentThreads": 0.0, + "unpublishedApplicationDetail": { "appPositioning": { "type": "FIXED" } }, + "publishedApplicationDetail": { "appPositioning": { "type": "FIXED" } }, + "color": "#C7F3F0", + "icon": "website", + "slug": "faultdsl", + "unpublishedCustomJSLibs": [ + { + "uidString": "xmlParser_https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js" + } + ], + "publishedCustomJSLibs": [], + "evaluationVersion": 2.0, + "applicationVersion": 2.0, + "collapseInvisibleWidgets": true, + "isManualUpdate": false, + "deleted": false + }, + "datasourceList": [ + { + "datasourceConfiguration": { + "connection": { + "mode": "READ_WRITE", + "ssl": { "authType": "DEFAULT" } + }, + "endpoints": [ + { "host": "mockdb.internal.appsmith.com", "port": 5432.0 } + ] + }, + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "isTemplate": true, + "deleted": false, + "gitSyncId": "61b6d49e33c6ae6163af2716_62a720d884b913372519bc5e" + } + ], + "customJSLibList": [ + { + "name": "xmlParser", + "uidString": "xmlParser_https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js", + "accessor": ["xmlParser"], + "url": "https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js", + "version": "3.17.5", + "defs": "{\"!name\":\"LIB/xmlParser\",\"xmlParser\":{\"parse\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertTonimn\":{\"!type\":\"fn()\",\"prototype\":{}},\"getTraversalObj\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertToJson\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertToJsonString\":{\"!type\":\"fn()\",\"prototype\":{}},\"validate\":{\"!type\":\"fn()\",\"prototype\":{}},\"j2xParser\":{\"!type\":\"fn()\",\"prototype\":{\"parse\":{\"!type\":\"fn()\",\"prototype\":{}},\"j2x\":{\"!type\":\"fn()\",\"prototype\":{}}}},\"parseToNimn\":{\"!type\":\"fn()\",\"prototype\":{}}}}", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "pageList": [ + { + "unpublishedPage": { + "name": "Admin", + "slug": "admin", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 1160.0, + "snapColumns": 64.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 1080.0, + "containerStyle": "none", + "snapRows": 66.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 89.0, + "minHeight": 670.0, + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [ + { + "boxShadow": "none", + "widgetName": "Container2CopyCopy1", + "borderColor": "transparent", + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.1977dca3370505e2db3a8e44cfd54907.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 27.0, + "bottomRow": 42.0, + "parentRowSpace": 10.0, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "leftColumn": 15.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Canvas2CopyCopy", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 150.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 150.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Image4CopyCopy", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 0.0, + "bottomRow": 5.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/group-1000004181.svg", + "key": "6j28hyj8ew", + "image": "", + "isDeprecated": false, + "rightColumn": 13.0, + "objectFit": "contain", + "widgetId": "qfjwgwe05v", + "isVisible": true, + "version": 1.0, + "parentId": "w0jg0594ue", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "widgetName": "Text1CopyCopyCopy", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b523e6f70ba6f40a10fc2c7c5b5.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 9.0, + "bottomRow": 13.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 4.3310546875, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "fontFamily" } + ], + "shouldTruncate": false, + "text": "{{appsmith.store.completedCount}}", + "key": "8ao8442ejy", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "6fvp0cwnnf", + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "w0jg0594ue", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "maxDynamicHeight": 9000.0, + "fontSize": "1.875rem", + "minDynamicHeight": 4.0 + }, + { + "widgetName": "Text1Copy1Copy", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b523e6f70ba6f40a10fc2c7c5b5.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 5.0, + "bottomRow": 9.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 4.3310546875, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "fontFamily" }], + "shouldTruncate": false, + "text": "Completed", + "key": "8ao8442ejy", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "h7p3oz17ig", + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "w0jg0594ue", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + } + ], + "key": "iv16tz47h6", + "isDeprecated": false, + "rightColumn": 475.5, + "detachFromLayout": true, + "widgetId": "w0jg0594ue", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "containerStyle": "none", + "isVisible": true, + "version": 1.0, + "parentId": "aryazglzwa", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + ], + "borderWidth": "1", + "key": "i2gkdaesc8", + "backgroundColor": "#E6E9F5", + "isDeprecated": false, + "rightColumn": 30.0, + "dynamicHeight": "FIXED", + "widgetId": "aryazglzwa", + "containerStyle": "card", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Container2Copy", + "borderColor": "transparent", + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.1977dca3370505e2db3a8e44cfd54907.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 10.0, + "bottomRow": 25.0, + "parentRowSpace": 10.0, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "leftColumn": 15.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Canvas2Copy", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 150.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 150.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Image4Copy", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 0.0, + "bottomRow": 5.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/group-1000004180.svg", + "key": "6j28hyj8ew", + "image": "", + "isDeprecated": false, + "rightColumn": 11.0, + "objectFit": "contain", + "widgetId": "sy10nyyznt", + "isVisible": true, + "version": 1.0, + "parentId": "ijzsvhm730", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "widgetName": "Text1CopyCopy", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b523e6f70ba6f40a10fc2c7c5b5.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 9.0, + "bottomRow": 13.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 4.3310546875, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "fontFamily" } + ], + "shouldTruncate": false, + "text": "{{appsmith.store.hoursSum}}", + "key": "8ao8442ejy", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "hcxltom53y", + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "ijzsvhm730", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "maxDynamicHeight": 9000.0, + "fontSize": "1.875rem", + "minDynamicHeight": 4.0 + }, + { + "widgetName": "Text1Copy1", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b523e6f70ba6f40a10fc2c7c5b5.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 5.0, + "bottomRow": 9.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 4.3310546875, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "fontFamily" }], + "shouldTruncate": false, + "text": "Total Hours", + "key": "8ao8442ejy", + "isDeprecated": false, + "rightColumn": 63.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "eie7hl9s3v", + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "ijzsvhm730", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + } + ], + "key": "iv16tz47h6", + "isDeprecated": false, + "rightColumn": 475.5, + "detachFromLayout": true, + "widgetId": "ijzsvhm730", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "containerStyle": "none", + "isVisible": true, + "version": 1.0, + "parentId": "5m9lcia6q3", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + ], + "borderWidth": "1", + "key": "i2gkdaesc8", + "backgroundColor": "#E6E9F5", + "isDeprecated": false, + "rightColumn": 30.0, + "dynamicHeight": "FIXED", + "widgetId": "5m9lcia6q3", + "containerStyle": "card", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "HeadingCopy", + "dynamicPropertyPathList": [{ "key": "fontSize" }], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 2.0, + "bottomRow": 6.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 16.62109375, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "leftColumn": 15.0, + "dynamicBindingPathList": [], + "truncateButtonColor": "#FFC13D", + "text": "Work Orders", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 52.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "cxkv9q70wz", + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#003B4A", + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.7rem", + "minDynamicHeight": 4.0 + }, + { + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b523e6f70ba6f40a10fc2c7c5b5.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 6.0, + "bottomRow": 10.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "leftColumn": 15.0, + "dynamicBindingPathList": [{ "key": "fontFamily" }], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Add and manage work orders", + "key": "p0uhc3c013", + "isDeprecated": false, + "rightColumn": 45.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "jify2p8j5i", + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "originalTopRow": 6.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "maxDynamicHeight": 9000.0, + "originalBottomRow": 10.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "selectAgent", + "isFilterable": false, + "dynamicPropertyPathList": [ + { "key": "onOptionChange" }, + { "key": "sourceData" } + ], + "displayName": "Select", + "iconSVG": "/static/media/icon.bd99caba.svg", + "labelText": "", + "topRow": 46.0, + "bottomRow": 50.0, + "parentRowSpace": 10.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "hideCard": false, + "defaultOptionValue": "", + "animateLoading": true, + "parentColumnSpace": 12.688995361328125, + "dynamicTriggerPathList": [{ "key": "onOptionChange" }], + "leftColumn": 17.0, + "dynamicBindingPathList": [ + { "key": "options" }, + { "key": "accentColor" } + ], + "placeholderText": "Agent", + "isDisabled": false, + "key": "fj5c87ojig", + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 31.0, + "dynamicHeight": "FIXED", + "widgetId": "g84nip1mxz", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0.375rem", + "maxDynamicHeight": 9000.0, + "onOptionChange": "{{ \nselectAgent.selectedOptionValue.length > 0 ? select_work_ordersAgent.run().then(() => {\nJSObject1.totalHoursCalc();\nJSObject1.completedCalc();\nJSObject1.equipChart()\t\n}) : select_work_orders.run().then(() => {\nJSObject1.totalHoursCalc();\nJSObject1.completedCalc();\nJSObject1.equipChart()\t\n}) \n}}\n\n", + "minDynamicHeight": 4.0, + "sourceData": "[\n {\n \"label\": {{select_agent.data[0].agent}},\n \"value\": {{select_agent.data[0].agent}}\n },\n\t {\n \"label\": {{select_agent.data[2].agent}},\n \"value\": {{select_agent.data[2].agent}}\n },\n\t {\n \"label\": {{select_agent.data[3].agent}},\n \"value\": {{select_agent.data[3].agent}}\n },\n\t {\n \"label\": {{select_agent.data[4].agent}},\n \"value\": {{select_agent.data[4].agent}}\n },\n\t {\n \"label\": {{select_agent.data[1].agent}},\n \"value\": {{select_agent.data[1].agent}}\n }\n]", + "optionLabel": "label", + "optionValue": "value" + }, + { + "boxShadow": "none", + "isVisibleDownload": false, + "iconSVG": "/static/media/icon.db8a9cbd.svg", + "topRow": 51.0, + "isSortable": true, + "onPageChange": "{{selectAgent.selectedOptionValue ? select_work_ordersAgent.run() : select_work_orders.run()}}", + "type": "TABLE_WIDGET", + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "tableData" }, + { "key": "primaryColumns.customColumn1.boxShadow" }, + { "key": "primaryColumns.customColumn1.buttonColor" }, + { "key": "primaryColumns.customColumn1.buttonLabel" }, + { "key": "primaryColumns.mat_cost.computedValue" }, + { "key": "primaryColumns.total_cost.computedValue" }, + { "key": "primaryColumns.work_id.computedValue" }, + { "key": "primaryColumns.customer_email.computedValue" }, + { "key": "primaryColumns.customer_name.computedValue" }, + { "key": "primaryColumns.hours.computedValue" }, + { "key": "primaryColumns.completed.computedValue" }, + { "key": "primaryColumns.maintenance_notes.computedValue" }, + { "key": "primaryColumns.agent.computedValue" }, + { "key": "primaryColumns.request_date.computedValue" }, + { "key": "primaryColumns.description.computedValue" }, + { "key": "primaryColumns.category.computedValue" }, + { "key": "primaryColumns.equipment.computedValue" }, + { "key": "accentColor" }, + { "key": "derivedColumns.customColumn1.buttonLabel" }, + { "key": "derivedColumns.customColumn1.menuColor" }, + { "key": "primaryColumns.customColumn1.menuColor" }, + { "key": "derivedColumns.customColumn1.borderRadius" }, + { "key": "primaryColumns.customColumn1.borderRadius" }, + { "key": "derivedColumns.customColumn1.boxShadow" }, + { "key": "totalRecordsCount" } + ], + "leftColumn": 15.0, + "delimiter": ",", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisibleFilters": true, + "isVisible": true, + "enableClientSideSearch": false, + "version": 3.0, + "totalRecordsCount": "{{selectAgent.selectedOptionValue ? select_work_ordersAgentPage.data.length : select_work_ordersPage.data.length}}", + "isLoading": false, + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "menuButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "iconButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + } + }, + "borderRadius": "0px", + "columnSizeMap": { + "task": 245.0, + "step": 62.0, + "status": 75.0, + "customColumn1": 82.0, + "work_id": 85.0, + "category": 198.0, + "equipment": 124.0, + "completed": 124.0 + }, + "widgetName": "workOrdersTable", + "defaultPageSize": 0.0, + "columnOrder": [ + "work_id", + "equipment", + "category", + "description", + "request_date", + "agent", + "maintenance_notes", + "completed", + "hours", + "customer_name", + "customer_email", + "total_cost", + "mat_cost", + "customColumn1" + ], + "dynamicPropertyPathList": [ + { "key": "onPageChange" }, + { "key": "onRowSelected" } + ], + "displayName": "Table", + "bottomRow": 107.0, + "parentRowSpace": 10.0, + "defaultSelectedRow": "0", + "hideCard": false, + "parentColumnSpace": 6.4609375, + "dynamicTriggerPathList": [ + { "key": "onRowSelected" }, + { "key": "onPageChange" }, + { "key": "primaryColumns.customColumn1.onClick" } + ], + "primaryColumns": { + "equipment": { + "index": 0.0, + "width": 150.0, + "id": "equipment", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Equipment", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.equipment))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "category": { + "index": 1.0, + "width": 150.0, + "id": "category", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Category", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.category))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "description": { + "index": 2.0, + "width": 150.0, + "id": "description", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "description", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.description))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "request_date": { + "index": 3.0, + "width": 150.0, + "id": "request_date", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "date", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Date", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.request_date))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none", + "iconName": "", + "outputFormat": "DD/MM/YYYY" + }, + "agent": { + "index": 4.0, + "width": 150.0, + "id": "agent", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Agent", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.agent))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "maintenance_notes": { + "index": 5.0, + "width": 150.0, + "id": "maintenance_notes", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "maintenance_notes", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.maintenance_notes))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "completed": { + "index": 6.0, + "width": 150.0, + "id": "completed", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Completed?", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.completed))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "hours": { + "index": 7.0, + "width": 150.0, + "id": "hours", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Hours spent", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.hours))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "customer_name": { + "index": 8.0, + "width": 150.0, + "id": "customer_name", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Customer Name", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.customer_name))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "customer_email": { + "index": 9.0, + "width": 150.0, + "id": "customer_email", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Customer Email", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.customer_email))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "work_id": { + "index": 0.0, + "width": 150.0, + "id": "work_id", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Work ID", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.work_id))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "total_cost": { + "index": 11.0, + "width": 150.0, + "id": "total_cost", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Total Cost", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.total_cost))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "mat_cost": { + "index": 12.0, + "width": 150.0, + "id": "mat_cost", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": false, + "isDisabled": false, + "isCellVisible": true, + "isDerived": false, + "label": "Material Cost", + "computedValue": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( currentRow.mat_cost))}}", + "cellBackground": "transparent", + "borderRadius": "0px", + "boxShadow": "none" + }, + "customColumn1": { + "index": 13.0, + "width": 150.0, + "id": "customColumn1", + "columnType": "iconButton", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": true, + "label": "Edit", + "computedValue": "", + "buttonStyle": "rgb(3, 179, 101)", + "labelColor": "#FFFFFF", + "buttonColor": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( appsmith.theme.colors.primaryColor))}}", + "borderRadius": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( appsmith.theme.borderRadius.appBorderRadius))}}", + "boxShadow": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( 'none'))}}", + "iconName": "edit", + "buttonLabel": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( 'Edit'))}}", + "buttonVariant": "TERTIARY", + "menuColor": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( appsmith.theme.colors.primaryColor))}}", + "onClick": "{{showModal('Modal1')}}", + "cellBackground": "transparent" + } + }, + "onRowSelected": "", + "key": "56eiocmwj5", + "derivedColumns": { + "customColumn1": { + "index": 13.0, + "width": 150.0, + "id": "customColumn1", + "columnType": "iconButton", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellVisible": true, + "isDerived": true, + "label": "Edit", + "computedValue": "", + "buttonStyle": "rgb(3, 179, 101)", + "labelColor": "#FFFFFF", + "buttonColor": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( appsmith.theme.colors.primaryColor))}}", + "borderRadius": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( appsmith.theme.borderRadius.appBorderRadius))}}", + "boxShadow": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( 'none'))}}", + "iconName": "edit", + "buttonLabel": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( 'Edit'))}}", + "buttonVariant": "TERTIARY", + "menuColor": "{{workOrdersTable.sanitizedTableData.map((currentRow) => ( appsmith.theme.colors.primaryColor))}}", + "onClick": "{{showModal('Modal1')}}", + "cellBackground": "transparent" + } + }, + "labelTextSize": "0.875rem", + "rightColumn": 63.0, + "textSize": "0.875rem", + "widgetId": "ijijwwgerq", + "tableData": "{{selectAgent.selectedOptionValue.length != 0 ? select_work_ordersAgent.data : select_work_orders.data}}", + "label": "Data", + "searchKey": "", + "parentId": "0", + "serverSidePaginationEnabled": true, + "renderMode": "CANVAS", + "horizontalAlignment": "LEFT", + "isVisibleSearch": true, + "isVisiblePagination": true, + "cellBackground": "transparent", + "verticalAlignment": "CENTER" + }, + { + "boxShadow": "none", + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.1977dca3370505e2db3a8e44cfd54907.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 0.0, + "bottomRow": 108.0, + "parentRowSpace": 10.0, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 1080.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 400.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Image2Copy2", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 28.0, + "bottomRow": 32.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 4.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/group-4394.svg", + "key": "20b6vlid8h", + "image": "", + "isDeprecated": false, + "rightColumn": 13.0, + "objectFit": "contain", + "widgetId": "3hphbu1n4x", + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "widgetName": "Button2Copy2", + "onClick": "{{navigateTo('Admin', {}, 'SAME_WINDOW')}}", + "buttonColor": "transparent", + "displayName": "Button", + "iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg", + "searchTags": ["click", "submit"], + "topRow": 28.0, + "bottomRow": 32.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 13.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "text": "Admin", + "isDisabled": false, + "key": "ea7apjwric", + "isDeprecated": false, + "rightColumn": 61.0, + "isDefaultClickDisabled": true, + "widgetId": "jspaw0xf26", + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "buttonVariant": "PRIMARY", + "placement": "START" + }, + { + "boxShadow": "none", + "widgetName": "Image2Copy1", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 23.0, + "bottomRow": 27.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 4.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/files.svg", + "key": "20b6vlid8h", + "image": "", + "isDeprecated": false, + "rightColumn": 13.0, + "objectFit": "contain", + "widgetId": "b9qc3b3ueh", + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "widgetName": "Button2Copy1", + "onClick": "{{navigateTo('My orders', {}, 'SAME_WINDOW')}}", + "buttonColor": "transparent", + "displayName": "Button", + "iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg", + "searchTags": ["click", "submit"], + "topRow": 23.0, + "bottomRow": 27.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 13.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "text": "My Work Orders", + "isDisabled": false, + "key": "ea7apjwric", + "isDeprecated": false, + "rightColumn": 60.0, + "isDefaultClickDisabled": true, + "widgetId": "7qi044xx0w", + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "buttonVariant": "PRIMARY", + "placement": "START" + }, + { + "boxShadow": "none", + "widgetName": "Image2Copy3", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 18.0, + "bottomRow": 22.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 4.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/listplus.svg", + "key": "20b6vlid8h", + "image": "", + "isDeprecated": false, + "rightColumn": 13.0, + "objectFit": "contain", + "widgetId": "z2rj62mi7h", + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "widgetName": "Button2Copy3", + "onClick": "{{navigateTo('Submit new order', {}, 'SAME_WINDOW')}}", + "buttonColor": "transparent", + "displayName": "Button", + "iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 13.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "text": "New Work Request", + "isDisabled": false, + "key": "ea7apjwric", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "exs2k6maug", + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "buttonVariant": "PRIMARY", + "placement": "START" + }, + { + "boxShadow": "none", + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 1.0, + "bottomRow": 6.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 3.7119140625, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 2.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/group-4465.svg", + "key": "20b6vlid8h", + "image": "", + "isDeprecated": false, + "rightColumn": 39.0, + "objectFit": "contain", + "widgetId": "cccyinonx7", + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "boxShadow": "none", + "widgetName": "Divider1", + "thickness": 2.0, + "displayName": "Divider", + "iconSVG": "/static/media/icon.cbe8f608ca868e1eb44607e5fbd4a9e5.svg", + "searchTags": ["line"], + "topRow": 6.0, + "bottomRow": 10.0, + "parentRowSpace": 10.0, + "type": "DIVIDER_WIDGET", + "capType": "nc", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 3.7119140625, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "key": "c3xzqeinqm", + "dividerColor": "#5E6C9E", + "orientation": "horizontal", + "strokeStyle": "solid", + "isDeprecated": false, + "rightColumn": 64.0, + "widgetId": "00rr0od1st", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "capSide": 0.0, + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + }, + { + "boxShadow": "none", + "widgetName": "Image2Copy4", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 13.0, + "bottomRow": 17.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 4.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/group-4405.svg", + "key": "20b6vlid8h", + "image": "", + "isDeprecated": false, + "rightColumn": 13.0, + "objectFit": "contain", + "widgetId": "ynyek2ui5b", + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "enableRotation": false + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "widgetName": "Button2", + "onClick": "{{navigateTo('Home Page', {}, 'SAME_WINDOW')}}", + "buttonColor": "transparent", + "displayName": "Button", + "iconSVG": "/static/media/icon.cca026338f1c8eb6df8ba03d084c2fca.svg", + "searchTags": ["click", "submit"], + "topRow": 13.0, + "bottomRow": 17.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 13.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "text": "Dashboard", + "isDisabled": false, + "key": "ea7apjwric", + "isDeprecated": false, + "rightColumn": 60.0, + "isDefaultClickDisabled": true, + "widgetId": "us1rl2o7qy", + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "buttonVariant": "PRIMARY", + "placement": "START" + }, + { + "boxShadow": "none", + "widgetName": "Image3", + "displayName": "Image", + "iconSVG": "/static/media/icon.52d8fb963abcb95c79b10f1553389f22.svg", + "topRow": 83.0, + "bottomRow": 105.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 4.021484375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "defaultImage": "https://s3.us-east-2.amazonaws.com/template.appsmith.com/bdd.png", + "key": "20b6vlid8h", + "image": "", + "isDeprecated": false, + "rightColumn": 64.0, + "objectFit": "contain", + "widgetId": "z3k3214q31", + "isVisible": true, + "version": 1.0, + "parentId": "syjkq3pgjy", + "renderMode": "CANVAS", + "isLoading": false, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "0px", + "enableRotation": false + } + ], + "key": "ok1ci5kt2b", + "isDeprecated": false, + "rightColumn": 475.5, + "detachFromLayout": true, + "widgetId": "syjkq3pgjy", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "containerStyle": "none", + "isVisible": true, + "version": 1.0, + "parentId": "umf2cog74w", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + ], + "borderWidth": "1", + "key": "7jawjh2cqc", + "backgroundColor": "#324479", + "isDeprecated": false, + "rightColumn": 14.0, + "dynamicHeight": "FIXED", + "widgetId": "umf2cog74w", + "containerStyle": "card", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Modal1", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.4975978e.svg", + "topRow": 10.0, + "bottomRow": 34.0, + "parentRowSpace": 10.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "animateLoading": true, + "parentColumnSpace": 11.3314208984375, + "leftColumn": 20.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Canvas10", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 770.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 778.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Container2CopyCopyCopy", + "borderColor": "", + "isCanvas": true, + "dynamicPropertyPathList": [ + { "key": "borderRadius" } + ], + "displayName": "Container", + "iconSVG": "/static/media/icon.1977dca3.svg", + "topRow": 0.0, + "bottomRow": 74.0, + "parentRowSpace": 10.0, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 18.0625, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Canvas2CopyCopyCopyCopy", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 730.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 740.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "widgetName": "Button1", + "onClick": "{{update_work_orders1.run(() => select_work_orders.run(), () => {})}}", + "buttonColor": "#2356A1", + "dynamicPropertyPathList": [ + { "key": "onClick" } + ], + "displayName": "Button", + "iconSVG": "/static/media/icon.cca02633.svg", + "topRow": 67.0, + "bottomRow": 72.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 6.1787109375, + "dynamicTriggerPathList": [ + { "key": "onClick" } + ], + "leftColumn": 44.0, + "dynamicBindingPathList": [], + "text": "Update", + "isDisabled": false, + "key": "fu5cfw8tbj", + "labelTextSize": "0.875rem", + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "ucz1joszft", + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0.375rem", + "buttonVariant": "PRIMARY", + "placement": "CENTER" + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopyCopyCopy1CopyCopy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 11.0, + "bottomRow": 15.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Customer Email", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "bfhd5kcsiq", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editcustEmail", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 11.0, + "bottomRow": 15.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "parentColumnSpace": 5.6962890625, + "dynamicTriggerPathList": [], + "fontFamily": "System Default", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "text" }], + "shouldTruncate": false, + "truncateButtonColor": "#FFC13D", + "text": "{{workOrdersTable.triggeredRow.customer_email}}", + "key": "sf3h3c9rxg", + "labelTextSize": "0.875rem", + "rightColumn": 60.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "6l5jntr587", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldTruncate": true, + "overflow": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopyCopyCopy1Copy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 7.0, + "bottomRow": 11.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Customer Name", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "k6m249v6fn", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editcustName", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 7.0, + "bottomRow": 11.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "parentColumnSpace": 5.6962890625, + "dynamicTriggerPathList": [], + "fontFamily": "System Default", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "text" }], + "shouldTruncate": false, + "truncateButtonColor": "#FFC13D", + "text": "{{workOrdersTable.triggeredRow.customer_name}}", + "key": "sf3h3c9rxg", + "labelTextSize": "0.875rem", + "rightColumn": 60.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "n5bu6y8d2w", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldTruncate": true, + "overflow": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editCompleted", + "isFilterable": true, + "displayName": "Select", + "iconSVG": "/static/media/icon.bd99caba.svg", + "labelText": "", + "topRow": 49.0, + "bottomRow": 53.0, + "parentRowSpace": 10.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "hideCard": false, + "defaultOptionValue": "{{ ((options, serverSideFiltering) => ( workOrdersTable.triggeredRow.completed|| ''))(editCompleted.options, editCompleted.serverSideFiltering) }}", + "animateLoading": true, + "parentColumnSpace": 5.853515625, + "dynamicTriggerPathList": [], + "leftColumn": 33.0, + "dynamicBindingPathList": [ + { "key": "defaultOptionValue" }, + { "key": "accentColor" } + ], + "placeholderText": "Select option", + "isDisabled": false, + "key": "o6darbc32i", + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 63.0, + "dynamicHeight": "FIXED", + "widgetId": "26sfdw8ffd", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "sourceData": "[\n {\n \"label\": \"Yes\",\n \"value\": \"Yes\"\n },\n {\n \"label\": \"No\",\n \"value\": \"No\"\n }\n]", + "optionLabel": "label", + "optionValue": "value", + "dynamicPropertyPathList": [ + { "key": "sourceData" } + ] + }, + { + "boxShadow": "none", + "widgetName": "editHoursUsed", + "displayName": "Input", + "iconSVG": "/static/media/icon.9f505595.svg", + "topRow": 53.0, + "bottomRow": 57.0, + "parentRowSpace": 10.0, + "autoFocus": false, + "type": "INPUT_WIDGET_V2", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 5.853515625, + "dynamicTriggerPathList": [], + "resetOnSubmit": true, + "leftColumn": 33.0, + "dynamicBindingPathList": [ + { "key": "defaultText" }, + { "key": "accentColor" } + ], + "labelStyle": "", + "inputType": "NUMBER", + "isDisabled": false, + "key": "frh9e8lhpg", + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 63.0, + "dynamicHeight": "FIXED", + "widgetId": "6e5isq741m", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": true, + "isVisible": true, + "label": "", + "version": 2.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "iconAlign": "left", + "defaultText": "{{workOrdersTable.triggeredRow.hours || ''}}", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editMC", + "displayName": "Currency Input", + "iconSVG": "/static/media/icon.f312efcb.svg", + "topRow": 57.0, + "bottomRow": 61.0, + "defaultCurrencyCode": "USD", + "parentRowSpace": 10.0, + "autoFocus": false, + "type": "CURRENCY_INPUT_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 5.853515625, + "dynamicTriggerPathList": [], + "resetOnSubmit": true, + "leftColumn": 33.0, + "dynamicBindingPathList": [ + { "key": "defaultText" }, + { "key": "accentColor" } + ], + "labelPosition": "Left", + "labelStyle": "", + "isDisabled": false, + "key": "3g9dnqeeie", + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 63.0, + "dynamicHeight": "FIXED", + "widgetId": "k59tc507ay", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": true, + "isVisible": true, + "label": "", + "allowCurrencyChange": false, + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "decimals": 0.0, + "iconAlign": "left", + "defaultText": "{{\nworkOrdersTable.triggeredRow.mat_cost ? workOrdersTable.triggeredRow.mat_cost : 0}}", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editTC", + "displayName": "Currency Input", + "iconSVG": "/static/media/icon.f312efcb.svg", + "topRow": 61.0, + "bottomRow": 65.0, + "defaultCurrencyCode": "USD", + "parentRowSpace": 10.0, + "autoFocus": false, + "type": "CURRENCY_INPUT_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 5.853515625, + "dynamicTriggerPathList": [], + "resetOnSubmit": true, + "leftColumn": 33.0, + "dynamicBindingPathList": [ + { "key": "defaultText" }, + { "key": "accentColor" } + ], + "labelPosition": "Left", + "labelStyle": "", + "isDisabled": false, + "key": "3g9dnqeeie", + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 63.0, + "dynamicHeight": "FIXED", + "widgetId": "09gy1q8fof", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": true, + "isVisible": true, + "label": "", + "allowCurrencyChange": false, + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "decimals": 0.0, + "iconAlign": "left", + "defaultText": "{{\nworkOrdersTable.triggeredRow.total_cost ? workOrdersTable.triggeredRow.total_cost : 0}}", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editEquipment", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 15.0, + "bottomRow": 19.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "parentColumnSpace": 5.6962890625, + "dynamicTriggerPathList": [], + "fontFamily": "System Default", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "text" }], + "shouldTruncate": false, + "truncateButtonColor": "#FFC13D", + "text": "{{workOrdersTable.triggeredRow.equipment}}", + "key": "sf3h3c9rxg", + "labelTextSize": "0.875rem", + "rightColumn": 48.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "2tpeti2iys", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldTruncate": true, + "overflow": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editorderCategory", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 19.0, + "bottomRow": 23.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "parentColumnSpace": 5.6962890625, + "dynamicTriggerPathList": [], + "fontFamily": "System Default", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "text" }], + "shouldTruncate": false, + "truncateButtonColor": "#FFC13D", + "text": "{{workOrdersTable.triggeredRow.category}}", + "key": "sf3h3c9rxg", + "labelTextSize": "0.875rem", + "rightColumn": 64.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "kxgtej06ta", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldTruncate": true, + "overflow": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editorderDesc", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 23.0, + "bottomRow": 27.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "TRUNCATE", + "parentColumnSpace": 5.6962890625, + "dynamicTriggerPathList": [], + "fontFamily": "System Default", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "text" }], + "shouldTruncate": false, + "truncateButtonColor": "#FFC13D", + "text": "{{workOrdersTable.triggeredRow.description}}", + "key": "sf3h3c9rxg", + "labelTextSize": "0.875rem", + "rightColumn": 64.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "mp159xsz1c", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldTruncate": true, + "overflow": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopy1CopyCopyCopyCopy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 57.0, + "bottomRow": 61.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Material costs", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "7vj1eoncah", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopyCopyCopyCopyCopy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 61.0, + "bottomRow": 65.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Total costs", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "9qfaoghg82", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopy2CopyCopy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 31.0, + "bottomRow": 35.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Agent", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "790vfcz8wc", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopy1CopyCopy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 35.0, + "bottomRow": 39.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Maintenance Notes", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "lv643q4grv", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopy1CopyCopyCopy1", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 49.0, + "bottomRow": 53.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Completed", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "365wjz96s9", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopyCopyCopyCopy1", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 53.0, + "bottomRow": 57.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Hours used", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "kqp5yxv9q7", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopy2Copy1", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 15.0, + "bottomRow": 19.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Equipment", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "u5bsq2tcyh", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopy1Copy1", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 19.0, + "bottomRow": 23.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Category", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "5elxnkbnz3", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopy1CopyCopy1", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 23.0, + "bottomRow": 27.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Description", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "9nbm9qanpb", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text2CopyCopyCopyCopyCopyCopy1", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 27.0, + "bottomRow": 31.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "dynamicBindingPathList": [], + "leftColumn": 1.0, + "truncateButtonColor": "#FFC13D", + "text": "Requested Date", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 32.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "x3pmvgu1ei", + "logBlackList": { + "isVisible": true, + "text": true, + "fontSize": true, + "fontStyle": true, + "textAlign": true, + "textColor": true, + "truncateButtonColor": true, + "widgetName": true, + "shouldScroll": true, + "shouldTruncate": true, + "version": true, + "animateLoading": true, + "type": true, + "hideCard": true, + "displayName": true, + "key": true, + "iconSVG": true, + "isCanvas": true, + "textStyle": true, + "dynamicBindingPathList": true, + "dynamicTriggerPathList": true, + "minHeight": true, + "widgetId": true, + "renderMode": true, + "isLoading": true, + "parentColumnSpace": true, + "parentRowSpace": true, + "leftColumn": true, + "rightColumn": true, + "topRow": true, + "bottomRow": true, + "parentId": true + }, + "isVisible": true, + "fontStyle": "", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.125rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "Text4CopyCopyCopyCopy", + "dynamicPropertyPathList": [ + { "key": "fontSize" } + ], + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 0.0, + "bottomRow": 4.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 10.1298828125, + "dynamicTriggerPathList": [], + "overflow": "NONE", + "fontFamily": "System Default", + "leftColumn": 1.0, + "dynamicBindingPathList": [{ "key": "text" }], + "truncateButtonColor": "#FFC13D", + "text": "Work Order ID: {{workOrdersTable.triggeredRow.work_id}}", + "key": "czyq0gtp0e", + "labelTextSize": "0.875rem", + "rightColumn": 40.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "lk7gi111se", + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "fontSize": "1.5rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editRequestedDate", + "minDate": "1920-12-31T18:30:00.000Z", + "dateFormat": "YYYY-MM-DD", + "dynamicPropertyPathList": [ + { "key": "defaultDate" } + ], + "displayName": "DatePicker", + "iconSVG": "/static/media/icon.300e5ab8.svg", + "topRow": 27.0, + "bottomRow": 31.0, + "shortcuts": false, + "parentRowSpace": 10.0, + "type": "DATE_PICKER_WIDGET2", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 5.853515625, + "dynamicTriggerPathList": [], + "leftColumn": 32.0, + "dynamicBindingPathList": [ + { "key": "defaultDate" }, + { "key": "accentColor" } + ], + "isDisabled": false, + "key": "g6ypr5b6bx", + "labelTextSize": "1rem", + "isRequired": false, + "rightColumn": 53.0, + "defaultDate": "{{\nworkOrdersTable.triggeredRow.request_date ? \nmoment(workOrdersTable.triggeredRow.request_date, \"YYYY-MM-DD\") : new Date().toISOString() }}", + "dynamicHeight": "FIXED", + "widgetId": "ougwj8lmur", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "datePickerType": "DATE_PICKER", + "label": "", + "version": 2.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "timePrecision": "None", + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "firstDayOfWeek": 0.0, + "closeOnSelection": true, + "maxDate": "2121-12-31T18:29:00.000Z", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "IconButton3", + "onClick": "{{closeModal('Modal1')}}", + "buttonColor": "#2E3D49", + "displayName": "Icon Button", + "iconSVG": "/static/media/icon.1a0c634a.svg", + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "leftColumn": 55.0, + "dynamicBindingPathList": [], + "iconSize": 24.0, + "isDisabled": false, + "key": "he5p9ovxh4", + "labelTextSize": "0.875rem", + "rightColumn": 63.0, + "iconName": "cross", + "widgetId": "c5tlnajq5j", + "isVisible": true, + "version": 1.0, + "parentId": "cryduleyoi", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "buttonVariant": "TERTIARY" + }, + { + "boxShadow": "none", + "widgetName": "editNotes", + "displayName": "Input", + "iconSVG": "/static/media/icon.9f505595.svg", + "topRow": 39.0, + "bottomRow": 49.0, + "parentRowSpace": 10.0, + "labelWidth": 5.0, + "autoFocus": false, + "type": "INPUT_WIDGET_V2", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 7.193359375, + "dynamicTriggerPathList": [], + "resetOnSubmit": true, + "leftColumn": 1.0, + "dynamicBindingPathList": [ + { "key": "defaultText" }, + { "key": "accentColor" } + ], + "labelPosition": "Left", + "labelStyle": "", + "inputType": "MULTI_LINE_TEXT", + "isDisabled": false, + "key": "8caqtpfmrx", + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 62.0, + "dynamicHeight": "FIXED", + "widgetId": "oixrmpekwv", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "label": "", + "version": 2.0, + "parentId": "cryduleyoi", + "labelAlignment": "left", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "iconAlign": "left", + "defaultText": "{{workOrdersTable.triggeredRow.maintenance_notes}}", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "widgetName": "editOrderAgent", + "isFilterable": true, + "dynamicPropertyPathList": [ + { "key": "sourceData" } + ], + "displayName": "Select", + "iconSVG": "/static/media/icon.bd99caba.svg", + "labelText": "", + "topRow": 31.0, + "bottomRow": 35.0, + "parentRowSpace": 10.0, + "labelWidth": 5.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "hideCard": false, + "defaultOptionValue": "{{ ((options, serverSideFiltering) => ( workOrdersTable.triggeredRow.agent || ''))(editOrderAgent.options, editOrderAgent.serverSideFiltering) }}", + "animateLoading": true, + "parentColumnSpace": 7.193359375, + "dynamicTriggerPathList": [ + { "key": "onOptionChange" } + ], + "leftColumn": 32.0, + "dynamicBindingPathList": [ + { "key": "options" }, + { "key": "defaultOptionValue" }, + { "key": "accentColor" } + ], + "labelPosition": "Left", + "placeholderText": "Select option", + "isDisabled": false, + "key": "vpduhjc9fo", + "labelTextSize": "1rem", + "isRequired": false, + "rightColumn": 64.0, + "dynamicHeight": "FIXED", + "widgetId": "n1di761cbl", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "parentId": "cryduleyoi", + "labelAlignment": "left", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "onOptionChange": "", + "minDynamicHeight": 4.0, + "sourceData": "[\n {\n \"label\": {{select_agent.data[0].agent}},\n \"value\": {{select_agent.data[0].agent}}\n },\n\t {\n \"label\": {{select_agent.data[2].agent}},\n \"value\": {{select_agent.data[2].agent}}\n },\n\t {\n \"label\": {{select_agent.data[3].agent}},\n \"value\": {{select_agent.data[3].agent}}\n },\n\t {\n \"label\": {{select_agent.data[4].agent}},\n \"value\": {{select_agent.data[4].agent}}\n },\n\t {\n \"label\": {{select_agent.data[1].agent}},\n \"value\": {{select_agent.data[1].agent}}\n }\n]", + "optionLabel": "label", + "optionValue": "value" + } + ], + "key": "ffadum178l", + "labelTextSize": "0.875rem", + "rightColumn": 433.5, + "detachFromLayout": true, + "widgetId": "cryduleyoi", + "containerStyle": "none", + "isVisible": true, + "version": 1.0, + "parentId": "oyphk6wrsq", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px" + } + ], + "borderWidth": "2", + "key": "6bzu8mpizb", + "labelTextSize": "0.875rem", + "backgroundColor": "#FFFFFF", + "rightColumn": 63.0, + "dynamicHeight": "FIXED", + "widgetId": "oyphk6wrsq", + "containerStyle": "card", + "isVisible": true, + "version": 1.0, + "parentId": "tewt2qrngx", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "15px", + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + } + ], + "isDisabled": false, + "key": "b8t0kybjms", + "labelTextSize": "0.875rem", + "rightColumn": 271.9541015625, + "detachFromLayout": true, + "widgetId": "tewt2qrngx", + "isVisible": true, + "version": 1.0, + "parentId": "77pbwrchpt", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px" + } + ], + "key": "ykhy01l1u0", + "height": 778.0, + "labelTextSize": "0.875rem", + "rightColumn": 44.0, + "detachFromLayout": true, + "dynamicHeight": "FIXED", + "widgetId": "77pbwrchpt", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "0px", + "maxDynamicHeight": 9000.0, + "width": 684.0, + "minDynamicHeight": 4.0 + }, + { + "setAdaptiveYMin": false, + "boxShadow": "none", + "widgetName": "equipmentPieChart", + "allowScroll": false, + "dynamicPropertyPathList": [{ "key": "isVisible" }], + "displayName": "Chart", + "iconSVG": "/static/media/icon.6adbe31e.svg", + "topRow": 10.0, + "bottomRow": 42.0, + "parentRowSpace": 10.0, + "type": "CHART_WIDGET", + "hideCard": false, + "chartData": { + "ofl8b3apgp": { + "seriesName": "", + "data": "{{appsmith.store.equipmentStats ? appsmith.store.equipmentStats : [] }}" + } + }, + "animateLoading": true, + "parentColumnSpace": 11.70703125, + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "chartData.ofl8b3apgp.data" } + ], + "customFusionChartConfig": { + "type": "column2d", + "dataSource": { + "chart": { + "caption": "Sales Report", + "xAxisName": "Product Line", + "yAxisName": "Revenue($)", + "theme": "fusion" + }, + "data": [ + { "label": "Product1", "value": 20000.0 }, + { "label": "Product2", "value": 22000.0 }, + { "label": "Product3", "value": 32000.0 } + ] + } + }, + "key": "yzaa8q6whh", + "labelTextSize": "0.875rem", + "rightColumn": 63.0, + "widgetId": "v0qy4koas9", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": "true", + "version": 1.0, + "parentId": "0", + "labelOrientation": "auto", + "renderMode": "CANVAS", + "isLoading": false, + "yAxisName": "", + "chartName": "Equipment", + "borderRadius": "0px", + "xAxisName": "", + "chartType": "PIE_CHART", + "showDataPointLabel": false, + "customEChartConfig": { + "dataset": { + "source": [ + ["Day", "Baidu", "Google", "Bing"], + ["Mon", 620.0, 120.0, 60.0], + ["Tue", 732.0, 132.0, 72.0], + ["Wed", 701.0, 101.0, 71.0], + ["Thu", 734.0, 134.0, 74.0], + ["Fri", 1090.0, 290.0, 190.0], + ["Sat", 1130.0, 230.0, 130.0], + ["Sun", 1120.0, 220.0, 110.0] + ] + }, + "tooltip": { + "trigger": "axis", + "axisPointer": { "type": "shadow" } + }, + "title": { + "text": "Search Engine Usage", + "left": "center", + "textStyle": { "width": 200.0, "overflow": "truncate" } + }, + "legend": { "top": 40.0, "type": "scroll" }, + "grid": { + "left": 15.0, + "right": 15.0, + "bottom": 30.0, + "top": 100.0, + "containLabel": true + }, + "xAxis": [{ "type": "category" }], + "yAxis": [{ "type": "value" }], + "series": [ + { "type": "bar", "stack": "Search Engine" }, + { "type": "bar", "stack": "Search Engine" }, + { "type": "bar", "stack": "Search Engine" } + ] + } + }, + { + "boxShadow": "none", + "widgetName": "IconButton4", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon Button", + "iconSVG": "/static/media/icon.1a0c634ac75f9fa6b6ae7a8df882a3ba.svg", + "searchTags": ["click", "submit"], + "topRow": 46.0, + "bottomRow": 50.0, + "parentRowSpace": 10.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 19.8125, + "dynamicTriggerPathList": [], + "leftColumn": 15.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "isDisabled": false, + "key": "qyezan59pn", + "isDeprecated": false, + "rightColumn": 17.0, + "iconName": "filter-list", + "widgetId": "6cy6b27i6c", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "buttonVariant": "TERTIARY" + } + ] + }, + "layoutOnLoadActions": [ + [ + { + "id": "Admin_agent_stats", + "name": "agent_stats", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": [], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_select_work_ordersPage", + "name": "select_work_ordersPage", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": [], + "timeoutInMillisecond": 10000.0 + } + ], + [ + { + "id": "Admin_JSObject1.completedCalc", + "name": "JSObject1.completedCalc", + "collectionId": "Admin_JSObject1", + "confirmBeforeExecute": false, + "pluginType": "JS", + "jsonPathKeys": [ + "async () => {\n await select_work_ordersPage.run();\n await select_work_ordersAgentPage.run();\n let count = 0;\n if (selectAgent.selectedOptionValue.length == 0) count = select_work_ordersPage.data.filter(item => item.completed == \"Yes\").length; else count = select_work_ordersAgentPage.data.filter(item => item.completed == \"Yes\").length;\n storeValue('completedCount', count);\n}" + ], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_JSObject1.equipChart", + "name": "JSObject1.equipChart", + "collectionId": "Admin_JSObject1", + "confirmBeforeExecute": false, + "pluginType": "JS", + "jsonPathKeys": [ + "async () => {\n await agent_stats.run();\n await agent_statsAgent.run();\n let chartData;\n if (selectAgent.selectedOptionValue.length == 0) chartData = agent_stats.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n }); else chartData = agent_statsAgent.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n });\n storeValue('equipmentStats', chartData);\n console.log(appsmith.store.equipmentStats);\n}" + ], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_JSObject1.totalHoursCalc", + "name": "JSObject1.totalHoursCalc", + "collectionId": "Admin_JSObject1", + "confirmBeforeExecute": false, + "pluginType": "JS", + "jsonPathKeys": [ + "async () => {\n let sum = 0;\n if (selectAgent.selectedOptionValue.length == 0) sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0); else sum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0);\n storeValue('hoursSum', sum);\n}" + ], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_select_work_ordersAgent", + "name": "select_work_ordersAgent", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": [ + " workOrdersTable.pageSize ", + " (workOrdersTable.pageNo - 1) * workOrdersTable.pageSize ", + "selectAgent.selectedOptionValue" + ], + "timeoutInMillisecond": 10000.0 + } + ], + [ + { + "id": "Admin_agent_statsAgent", + "name": "agent_statsAgent", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_completed_orders", + "name": "completed_orders", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_select_agent", + "name": "select_agent", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": [], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_select_work_orders", + "name": "select_work_orders", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": [ + "(workOrdersTable.pageNo - 1) * workOrdersTable.pageSize ", + " workOrdersTable.pageSize " + ], + "timeoutInMillisecond": 10000.0 + }, + { + "id": "Admin_select_work_ordersAgentPage", + "name": "select_work_ordersAgentPage", + "confirmBeforeExecute": false, + "pluginType": "DB", + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "timeoutInMillisecond": 10000.0 + } + ] + ], + "layoutOnLoadActionErrors": [], + "validOnPageLoadActions": true, + "id": "Admin", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [], + "isHidden": true + }, + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a963066542e4" + } + ], + "actionList": [ + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "total_hours", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT SUM(hours) FROM work_orders where agent={{selectAgent.selectedOptionLabel}};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionLabel"], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "total_hours", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT SUM(hours) FROM work_orders where agent={{selectAgent.selectedOptionLabel}};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionLabel"], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_total_hours", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a963066542f3" + }, + { + "pluginType": "JS", + "pluginId": "js-plugin", + "unpublishedAction": { + "name": "search", + "fullyQualifiedName": "JSObject1.search", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "organizationId": "61b6d49e33c6ae6163af2716", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "() => {\n if (selectAgent.selectedOptionValue.length == 0) {\n return select_work_orders.data;\n } else {\n return select_work_orders.data.filter(user => user.agent == selectAgent.selectedOptionLabel);\n }\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": false + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "() => {\n if (selectAgent.selectedOptionValue.length == 0) {\n return select_work_orders.data;\n } else {\n return select_work_orders.data.filter(user => user.agent == selectAgent.selectedOptionLabel);\n }\n}" + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "search", + "fullyQualifiedName": "JSObject1.search", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "organizationId": "61b6d49e33c6ae6163af2716", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "() => {\n if (selectAgent.selectedOptionValue.length == 0) {\n return select_work_orders.data;\n } else {\n return select_work_orders.data.filter(user => user.agent == selectAgent.selectedOptionLabel);\n }\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": false + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "() => {\n if (selectAgent.selectedOptionValue.length == 0) {\n return select_work_orders.data;\n } else {\n return select_work_orders.data.filter(user => user.agent == selectAgent.selectedOptionLabel);\n }\n}" + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_JSObject1.search", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a963066542ed" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "select_agent", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from agent", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "select_agent", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from agent", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_select_agent", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a963066542f5" + }, + { + "pluginType": "JS", + "pluginId": "js-plugin", + "unpublishedAction": { + "name": "totalHoursCalc", + "fullyQualifiedName": "JSObject1.totalHoursCalc", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "async () => {\n let sum = 0;\n if (selectAgent.selectedOptionValue.length == 0) sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0); else sum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0);\n storeValue('hoursSum', sum);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "async () => {\n let sum = 0;\n if (selectAgent.selectedOptionValue.length == 0) sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0); else sum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0);\n storeValue('hoursSum', sum);\n}" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "totalHoursCalc", + "fullyQualifiedName": "JSObject1.totalHoursCalc", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "async () => {\n let sum = 0;\n if (selectAgent.selectedOptionValue.length == 0) sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0); else sum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0);\n storeValue('hoursSum', sum);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "async () => {\n let sum = 0;\n if (selectAgent.selectedOptionValue.length == 0) sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0); else sum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n }, 0);\n storeValue('hoursSum', sum);\n}" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_JSObject1.totalHoursCalc", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654311" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "agent_stats", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT equipment, COUNT(*) FROM work_orders GROUP BY equipment;", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "agent_stats", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT equipment, COUNT(*) FROM work_orders GROUP BY equipment;", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_agent_stats", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a963066542f7" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "update_work_orders1", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "UPDATE work_orders\nSET request_date= {{editRequestedDate.formattedDate}}, \n\t\tagent={{editOrderAgent.selectedOptionValue}},\n\t\tmaintenance_notes= {{editNotes.text}},\n\t\tcompleted= {{editCompleted.selectedOptionValue}},\n\t\ttotal_cost= {{editTC.value}},\n\t\tmat_cost= {{editMC.value}},\n\t\thours= {{editHoursUsed.text}}\nWHERE work_id={{workOrdersTable.triggeredRow.work_id}};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "editHoursUsed.text", + "editTC.value", + "editRequestedDate.formattedDate", + "editMC.value", + "editCompleted.selectedOptionValue", + "editNotes.text", + "workOrdersTable.triggeredRow.work_id", + "editOrderAgent.selectedOptionValue" + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "update_work_orders1", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "UPDATE work_orders\nSET request_date= {{editRequestedDate.formattedDate}}, \n\t\tagent={{editOrderAgent.selectedOptionValue}},\n\t\tmaintenance_notes= {{editNotes.text}},\n\t\tcompleted= {{editCompleted.selectedOptionValue}},\n\t\ttotal_cost= {{editTC.value}},\n\t\tmat_cost= {{editMC.value}},\n\t\thours= {{editHoursUsed.text}}\nWHERE work_id={{workOrdersTable.triggeredRow.work_id}};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "editHoursUsed.text", + "editTC.value", + "editRequestedDate.formattedDate", + "editMC.value", + "editCompleted.selectedOptionValue", + "editNotes.text", + "workOrdersTable.triggeredRow.work_id", + "editOrderAgent.selectedOptionValue" + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_update_work_orders1", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a963066542fb" + }, + { + "pluginType": "JS", + "pluginId": "js-plugin", + "unpublishedAction": { + "name": "completedCalc", + "fullyQualifiedName": "JSObject1.completedCalc", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "async () => {\n await select_work_ordersPage.run();\n await select_work_ordersAgentPage.run();\n let count = 0;\n if (selectAgent.selectedOptionValue.length == 0) count = select_work_ordersPage.data.filter(item => item.completed == \"Yes\").length; else count = select_work_ordersAgentPage.data.filter(item => item.completed == \"Yes\").length;\n storeValue('completedCount', count);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "async () => {\n await select_work_ordersPage.run();\n await select_work_ordersAgentPage.run();\n let count = 0;\n if (selectAgent.selectedOptionValue.length == 0) count = select_work_ordersPage.data.filter(item => item.completed == \"Yes\").length; else count = select_work_ordersAgentPage.data.filter(item => item.completed == \"Yes\").length;\n storeValue('completedCount', count);\n}" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "completedCalc", + "fullyQualifiedName": "JSObject1.completedCalc", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "async () => {\n await select_work_ordersPage.run();\n await select_work_ordersAgentPage.run();\n let count = 0;\n if (selectAgent.selectedOptionValue.length == 0) count = select_work_ordersPage.data.filter(item => item.completed == \"Yes\").length; else count = select_work_ordersAgentPage.data.filter(item => item.completed == \"Yes\").length;\n storeValue('completedCount', count);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "async () => {\n await select_work_ordersPage.run();\n await select_work_ordersAgentPage.run();\n let count = 0;\n if (selectAgent.selectedOptionValue.length == 0) count = select_work_ordersPage.data.filter(item => item.completed == \"Yes\").length; else count = select_work_ordersAgentPage.data.filter(item => item.completed == \"Yes\").length;\n storeValue('completedCount', count);\n}" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_JSObject1.completedCalc", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654319" + }, + { + "pluginType": "JS", + "pluginId": "js-plugin", + "unpublishedAction": { + "name": "clear", + "fullyQualifiedName": "JSObject1.clear", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "() => {\n storeValue('hoursSum', null);\n storeValue('completedCount', null);\n storeValue('equipmentStats', null);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "() => {\n storeValue('hoursSum', null);\n storeValue('completedCount', null);\n storeValue('equipmentStats', null);\n}" + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "clear", + "fullyQualifiedName": "JSObject1.clear", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "() => {\n storeValue('hoursSum', null);\n storeValue('completedCount', null);\n storeValue('equipmentStats', null);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": false, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "() => {\n storeValue('hoursSum', null);\n storeValue('completedCount', null);\n storeValue('equipmentStats', null);\n}" + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_JSObject1.clear", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a9630665431f" + }, + { + "pluginType": "JS", + "pluginId": "js-plugin", + "unpublishedAction": { + "name": "equipChart", + "fullyQualifiedName": "JSObject1.equipChart", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "async () => {\n await agent_stats.run();\n await agent_statsAgent.run();\n let chartData;\n if (selectAgent.selectedOptionValue.length == 0) chartData = agent_stats.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n }); else chartData = agent_statsAgent.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n });\n storeValue('equipmentStats', chartData);\n console.log(appsmith.store.equipmentStats);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "async () => {\n await agent_stats.run();\n await agent_statsAgent.run();\n let chartData;\n if (selectAgent.selectedOptionValue.length == 0) chartData = agent_stats.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n }); else chartData = agent_statsAgent.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n });\n storeValue('equipmentStats', chartData);\n console.log(appsmith.store.equipmentStats);\n}" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "equipChart", + "fullyQualifiedName": "JSObject1.equipChart", + "datasource": { + "name": "UNUSED_DATASOURCE", + "pluginId": "js-plugin", + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "collectionId": "Admin_JSObject1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "async () => {\n await agent_stats.run();\n await agent_statsAgent.run();\n let chartData;\n if (selectAgent.selectedOptionValue.length == 0) chartData = agent_stats.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n }); else chartData = agent_statsAgent.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n });\n storeValue('equipmentStats', chartData);\n console.log(appsmith.store.equipmentStats);\n}", + "selfReferencingDataPaths": [], + "jsArguments": [], + "isAsync": true + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "async () => {\n await agent_stats.run();\n await agent_statsAgent.run();\n let chartData;\n if (selectAgent.selectedOptionValue.length == 0) chartData = agent_stats.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n }); else chartData = agent_statsAgent.data.map(gen => {\n return {\n x: gen.equipment,\n y: gen.count\n };\n });\n storeValue('equipmentStats', chartData);\n console.log(appsmith.store.equipmentStats);\n}" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_JSObject1.equipChart", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a9630665431d" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "completed_orders", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT COUNT(*) FROM work_orders WHERE agent= {{selectAgent.selectedOptionValue}} and completed ='Yes';", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "completed_orders", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT COUNT(*) FROM work_orders WHERE agent= {{selectAgent.selectedOptionValue}} and completed ='Yes';", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_completed_orders", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a9630665430f" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "select_work_ordersAgent", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders where agent = {{selectAgent.selectedOptionValue}} limit {{ workOrdersTable.pageSize }} offset {{ (workOrdersTable.pageNo - 1) * workOrdersTable.pageSize }};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + " workOrdersTable.pageSize ", + " (workOrdersTable.pageNo - 1) * workOrdersTable.pageSize ", + "selectAgent.selectedOptionValue" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "select_work_ordersAgent", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders where agent = {{selectAgent.selectedOptionValue}} limit {{ workOrdersTable.pageSize }} offset {{ (workOrdersTable.pageNo - 1) * workOrdersTable.pageSize }};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + " workOrdersTable.pageSize ", + " (workOrdersTable.pageNo - 1) * workOrdersTable.pageSize ", + "selectAgent.selectedOptionValue" + ], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_select_work_ordersAgent", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654313" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "select_work_orders", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders limit {{ workOrdersTable.pageSize }} offset {{(workOrdersTable.pageNo - 1) * workOrdersTable.pageSize }};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "(workOrdersTable.pageNo - 1) * workOrdersTable.pageSize ", + " workOrdersTable.pageSize " + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "select_work_orders", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders limit {{ workOrdersTable.pageSize }} offset {{(workOrdersTable.pageNo - 1) * workOrdersTable.pageSize }};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [ + "(workOrdersTable.pageNo - 1) * workOrdersTable.pageSize ", + " workOrdersTable.pageSize " + ], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_select_work_orders", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654305" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "select_work_ordersPage", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders;", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "select_work_ordersPage", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders;", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_select_work_ordersPage", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654315" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "agent_statsAgent", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT equipment, COUNT(*) FROM work_orders WHERE agent= {{selectAgent.selectedOptionValue}} GROUP BY equipment;", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "agent_statsAgent", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "SELECT equipment, COUNT(*) FROM work_orders WHERE agent= {{selectAgent.selectedOptionValue}} GROUP BY equipment;", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_agent_statsAgent", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a9630665431b" + }, + { + "pluginType": "DB", + "pluginId": "postgres-plugin", + "unpublishedAction": { + "name": "select_work_ordersAgentPage", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Admin", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders where agent = {{selectAgent.selectedOptionValue}};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "publishedAction": { + "name": "select_work_ordersAgentPage", + "datasource": { + "name": "Mock_DB", + "pluginId": "postgres-plugin", + "messages": [], + "isAutoGenerated": false, + "id": "Mock_DB", + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "encodeParamsToggle": true, + "body": "select * from work_orders where agent = {{selectAgent.selectedOptionValue}};", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }] + }, + "executeOnLoad": true, + "dynamicBindingPathList": [{ "key": "body" }], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": ["selectAgent.selectedOptionValue"], + "userSetOnLoad": true, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2024-03-11T05:56:19Z" + }, + "id": "Admin_select_work_ordersAgentPage", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654317" + } + ], + "actionCollectionList": [ + { + "unpublishedCollection": { + "name": "JSObject1", + "pageId": "Admin", + "pluginId": "js-plugin", + "pluginType": "JS", + "actions": [], + "archivedActions": [], + "body": "export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\t\n\tclear: () => {\n\t\tstoreValue('hoursSum',null);\n\t\tstoreValue('completedCount',null);\n\t\tstoreValue('equipmentStats',null);\n\t},\n\t\n\tsearch: () => {\n\t\tif(selectAgent.selectedOptionValue.length==0){\n\t\t\treturn select_work_orders.data\n\t\t}\n\t\telse{\n\t\t\treturn(select_work_orders.data.filter(user => user.agent==(selectAgent.selectedOptionLabel)))\n\t\t}\n\t},\n\t\n\ttotalHoursCalc: async() => {\n\t\tlet sum = 0\n\t\tif(selectAgent.selectedOptionValue.length == 0)\n\t sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n}, 0);\n\t\telse \n\t\t\tsum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n}, 0);\n\t\t\t storeValue('hoursSum',sum);\n\n\t},\n\n\tcompletedCalc: async() => {\t\n\t\tawait select_work_ordersPage.run()\n\t\tawait select_work_ordersAgentPage.run()\n\t\tlet count = 0\n\n\t\tif(selectAgent.selectedOptionValue.length == 0)\n\t count = (select_work_ordersPage.data.filter((item) => item.completed == \"Yes\")).length;\n\t\telse \n\t\tcount = (select_work_ordersAgentPage.data.filter((item) => item.completed == \"Yes\")).length;\n\n storeValue('completedCount',count);\n\t},\n\t\n\tequipChart: async() => {\n\t\tawait agent_stats.run()\n\t\tawait agent_statsAgent.run()\n\t\tlet chartData\n\t\tif(selectAgent.selectedOptionValue.length == 0)\n\t chartData = agent_stats.data.map((gen) => {return {x: gen.equipment, y: gen.count }})\n\n\t\telse \n\t\tchartData = agent_statsAgent.data.map((gen) => {return {x: gen.equipment, y: gen.count }})\n\n storeValue('equipmentStats',chartData);\n\t\tconsole.log(appsmith.store.equipmentStats)\n\t}\n\t\n}", + "variables": [ + { "name": "myVar1", "value": "[]" }, + { "name": "myVar2", "value": "{}" } + ], + "userPermissions": [] + }, + "publishedCollection": { + "name": "JSObject1", + "pluginId": "js-plugin", + "pluginType": "JS", + "actions": [], + "archivedActions": [], + "body": "export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\t\n\tclear: () => {\n\t\tstoreValue('hoursSum',null);\n\t\tstoreValue('completedCount',null);\n\t\tstoreValue('equipmentStats',null);\n\t},\n\t\n\tsearch: () => {\n\t\tif(selectAgent.selectedOptionValue.length==0){\n\t\t\treturn select_work_orders.data\n\t\t}\n\t\telse{\n\t\t\treturn(select_work_orders.data.filter(user => user.agent==(selectAgent.selectedOptionLabel)))\n\t\t}\n\t},\n\t\n\ttotalHoursCalc: async() => {\n\t\tlet sum = 0\n\t\tif(selectAgent.selectedOptionValue.length == 0)\n\t sum = select_work_ordersPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n}, 0);\n\t\telse \n\t\t\tsum = select_work_ordersAgentPage.data.reduce((accumulator, object) => {\n return accumulator + object.hours;\n}, 0);\n\t\t\t storeValue('hoursSum',sum);\n\n\t},\n\n\tcompletedCalc: async() => {\t\n\t\tawait select_work_ordersPage.run()\n\t\tawait select_work_ordersAgentPage.run()\n\t\tlet count = 0\n\n\t\tif(selectAgent.selectedOptionValue.length == 0)\n\t count = (select_work_ordersPage.data.filter((item) => item.completed == \"Yes\")).length;\n\t\telse \n\t\tcount = (select_work_ordersAgentPage.data.filter((item) => item.completed == \"Yes\")).length;\n\n storeValue('completedCount',count);\n\t},\n\t\n\tequipChart: async() => {\n\t\tawait agent_stats.run()\n\t\tawait agent_statsAgent.run()\n\t\tlet chartData\n\t\tif(selectAgent.selectedOptionValue.length == 0)\n\t chartData = agent_stats.data.map((gen) => {return {x: gen.equipment, y: gen.count }})\n\n\t\telse \n\t\tchartData = agent_statsAgent.data.map((gen) => {return {x: gen.equipment, y: gen.count }})\n\n storeValue('equipmentStats',chartData);\n\t\tconsole.log(appsmith.store.equipmentStats)\n\t}\n\t\n}", + "variables": [ + { "name": "myVar1", "value": "[]" }, + { "name": "myVar2", "value": "{}" } + ], + "userPermissions": [] + }, + "id": "Admin_JSObject1", + "deleted": false, + "gitSyncId": "65ee9ce9a207a963066542c7_65ee9d03a207a96306654325" + } + ], + "editModeTheme": { + "name": "Default-New", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + }, + "publishedTheme": { + "name": "Default-New", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + } +} From 658ea94ae6346c5c49be771ca5ff0713ed221414 Mon Sep 17 00:00:00 2001 From: Nidhi Date: Wed, 13 Mar 2024 10:34:44 +0530 Subject: [PATCH 16/25] chore: Split changes for overridden package import (#31712) --- ...tionCollectionImportableServiceCEImpl.java | 39 ++++++++---------- .../ArtifactBasedImportableServiceCE.java | 12 ++++++ .../NewActionImportableServiceCEImpl.java | 41 ++++++++----------- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java index 63bd3710d0..9f18888299 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java @@ -75,7 +75,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic ImportingMetaDTO importingMetaDTO, MappedImportableResourcesDTO mappedImportableResourcesDTO) { - ArtifactBasedImportableService artifactBasedExportableService = + ArtifactBasedImportableService artifactBasedImportableService = getArtifactBasedImportableService(importingMetaDTO); Mono> importedActionCollectionMono = Mono.just(importedActionCollectionList); @@ -83,14 +83,14 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic if (importingMetaDTO.getAppendToArtifact()) { importedActionCollectionMono = importedActionCollectionMono.map(importedActionCollections -> { List importedContextNames = - artifactBasedExportableService.getImportedContextNames(mappedImportableResourcesDTO); + artifactBasedImportableService.getImportedContextNames(mappedImportableResourcesDTO); Map newToOldNameMap = mappedImportableResourcesDTO.getContextNewNameToOldName(); for (String newContextName : importedContextNames) { String oldContextName = newToOldNameMap.get(newContextName); if (!newContextName.equals(oldContextName)) { - artifactBasedExportableService.renameContextInImportableResources( + artifactBasedImportableService.renameContextInImportableResources( importedActionCollections, oldContextName, newContextName); } } @@ -125,7 +125,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic ImportingMetaDTO importingMetaDTO, MappedImportableResourcesDTO mappedImportableResourcesDTO) { - ArtifactBasedImportableService artifactBasedExportableService = + ArtifactBasedImportableService artifactBasedImportableService = getArtifactBasedImportableService(importingMetaDTO); /* Mono.just(importableArtifact) is created to avoid the eagerly fetching of existing actionCollections @@ -138,7 +138,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic // Map of gitSyncId to actionCollection of the existing records in DB Mono> actionCollectionsInCurrentArtifactMono = - artifactBasedExportableService + artifactBasedImportableService .getExistingResourcesInCurrentArtifactFlux(artifact) .filter(collection -> collection.getGitSyncId() != null) .collectMap(ActionCollection::getGitSyncId); @@ -147,7 +147,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic if (artifact.getGitArtifactMetadata() != null) { final String defaultArtifactId = artifact.getGitArtifactMetadata().getDefaultArtifactId(); - actionCollectionsInBranchesMono = artifactBasedExportableService + actionCollectionsInBranchesMono = artifactBasedImportableService .getExistingResourcesInOtherBranchesFlux(defaultArtifactId, artifact.getId()) .filter(actionCollection -> actionCollection.getGitSyncId() != null) .collectMap(ActionCollection::getGitSyncId); @@ -190,10 +190,11 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic if (actionsCollectionsInBranches.containsKey(actionCollection.getGitSyncId())) { branchedActionCollection = - getExistingCollectionInOtherBranchesForImportedCollection( - mappedImportableResourcesDTO, - actionsCollectionsInBranches, - actionCollection); + artifactBasedImportableService + .getExistingEntityInOtherBranchForImportedEntity( + mappedImportableResourcesDTO, + actionsCollectionsInBranches, + actionCollection); } Context defaultContext = populateIdReferencesAndReturnDefaultContext( @@ -209,10 +210,11 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic // Since the resource is already present in DB, just update resource ActionCollection existingActionCollection = - getExistingCollectionInCurrentBranchForImportedCollection( - mappedImportableResourcesDTO, - actionsCollectionsInCurrentArtifact, - actionCollection); + artifactBasedImportableService + .getExistingEntityInCurrentBranchForImportedEntity( + mappedImportableResourcesDTO, + actionsCollectionsInCurrentArtifact, + actionCollection); updateExistingCollection( importingMetaDTO, @@ -226,7 +228,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic .getSavedActionCollectionMap() .put(idFromJsonFile, existingActionCollection); } else { - artifactBasedExportableService.createNewResource( + artifactBasedImportableService.createNewResource( importingMetaDTO, actionCollection, defaultContext); populateDomainMappedReferences(mappedImportableResourcesDTO, actionCollection); @@ -374,13 +376,6 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic return actionsCollectionsInCurrentArtifact.get(actionCollection.getGitSyncId()); } - protected ActionCollection getExistingCollectionInOtherBranchesForImportedCollection( - MappedImportableResourcesDTO mappedImportableResourcesDTO, - Map actionsCollectionsInOtherArtifact, - ActionCollection actionCollection) { - return actionsCollectionsInOtherArtifact.get(actionCollection.getGitSyncId()); - } - protected boolean existingArtifactContainsCollection( Map actionsCollectionsInCurrentArtifact, ActionCollection actionCollection) { return actionCollection.getGitSyncId() != null diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java index e0aeee6b44..ff8f44ab5b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java @@ -30,4 +30,16 @@ public interface ArtifactBasedImportableServiceCE entityInCurrentArtifact, + T entity) { + return entityInCurrentArtifact.get(entity.getGitSyncId()); + } + + default T getExistingEntityInOtherBranchForImportedEntity( + MappedImportableResourcesDTO mappedImportableResourcesDTO, Map entityInOtherArtifact, T entity) { + return entityInOtherArtifact.get(entity.getGitSyncId()); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java index 471416ba37..90eddc072d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java @@ -202,7 +202,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE artifactBasedExportableService = + ArtifactBasedImportableService artifactBasedImportableService = getArtifactBasedImportableService(importingMetaDTO); Mono> importedNewActionMono = Mono.justOrEmpty(importedNewActions); @@ -210,14 +210,14 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE { List importedContextNames = - artifactBasedExportableService.getImportedContextNames(mappedImportableResourcesDTO); + artifactBasedImportableService.getImportedContextNames(mappedImportableResourcesDTO); Map newToOldNameMap = mappedImportableResourcesDTO.getContextNewNameToOldName(); for (String newContextName : importedContextNames) { String oldContextName = newToOldNameMap.get(newContextName); if (!newContextName.equals(oldContextName)) { - artifactBasedExportableService.renameContextInImportableResources( + artifactBasedImportableService.renameContextInImportableResources( importedNewActionList, oldContextName, newContextName); } } @@ -248,7 +248,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE artifactBasedExportableService = + ArtifactBasedImportableService artifactBasedImportableService = getArtifactBasedImportableService(importingMetaDTO); /* Mono.just(importableArtifact) is created to avoid the eagerly fetching of existing actions @@ -258,7 +258,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE> actionsInCurrentArtifactMono = artifactBasedExportableService + Mono> actionsInCurrentArtifactMono = artifactBasedImportableService .getExistingResourcesInCurrentArtifactFlux(artifact) .filter(collection -> collection.getGitSyncId() != null) .collectMap(NewAction::getGitSyncId); @@ -268,7 +268,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE newAction.getGitSyncId() != null) .collectMap(NewAction::getGitSyncId); @@ -305,8 +305,9 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE actionsInCurrentArtifact, - NewAction newAction) { - return actionsInCurrentArtifact.get(newAction.getGitSyncId()); - } - - protected NewAction getExistingActionInOtherBranchForImportedAction( - MappedImportableResourcesDTO mappedImportableResourcesDTO, - Map actionsInOtherArtifact, - NewAction newAction) { - return actionsInOtherArtifact.get(newAction.getGitSyncId()); - } - protected boolean existingArtifactContainsAction( Map actionsInCurrentArtifact, NewAction newAction) { return newAction.getGitSyncId() != null && actionsInCurrentArtifact.containsKey(newAction.getGitSyncId()); From 16175277994d7c98f8f7b3c896ed0360f4403345 Mon Sep 17 00:00:00 2001 From: Rahul Barwal Date: Wed, 13 Mar 2024 10:47:45 +0530 Subject: [PATCH 17/25] fix: Handle widget selection on modal closure when url changes. (#31702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Root cause In the case of `Vehicle maintenence app` the problem was when you had modal open and clicked on appsmith logo - it triggered evaluations, which in turn closed the modal -> and modal saga called select widget saga (to select the main container) This PR adds a check in the widget selection saga to ensure that we dont run the selection logic if we are not on the editor url. Fixes #31614 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Widget,@tag.Modal,@tag.MainContainer,@tag.Container" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `f9aee9ac5e03c556782df6b8306ddc75261e2d10` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit ## Summary by CodeRabbit - **Refactor** - Improved the selection process of widgets by checking if the user is on the editor page, enhancing the app usability and performance. - Added a condition to the selectWidgetSaga function to ensure actions are performed only when the current URL is on the editor page. --- app/client/src/sagas/WidgetSelectionSagas.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/client/src/sagas/WidgetSelectionSagas.ts b/app/client/src/sagas/WidgetSelectionSagas.ts index 5b957ffbbf..ecaf44e9e2 100644 --- a/app/client/src/sagas/WidgetSelectionSagas.ts +++ b/app/client/src/sagas/WidgetSelectionSagas.ts @@ -55,6 +55,7 @@ import { getModalWidgetType } from "selectors/widgetSelectors"; import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; import { getWidgetSelectorByWidgetId } from "selectors/layoutSystemSelectors"; +import { getAppViewerPageIdFromPath } from "@appsmith/pages/Editor/Explorer/helpers"; // The following is computed to be used in the entity explorer // Every time a widget is selected, we need to expand widget entities @@ -67,8 +68,17 @@ function* selectWidgetSaga(action: ReduxAction) { payload = [], selectionRequestType, } = action.payload; + /** + * Apart from the normal selection request by a user on canvas, there are other ways which can trigger selection + * e.g. when a modal closes in the editor -> we select the main container. + * One way modal closes is because user navigates to home page using the appsmith icon. In this case, we don't want the selection process to trigger. + * This also safeguards against the case where the selection process is triggered by a non-canvas click where user moves out of editor. + * */ - if (payload.some(isInvalidSelectionRequest)) { + const isOnEditorURL = !!getAppViewerPageIdFromPath( + window.location.pathname, + ); + if (payload.some(isInvalidSelectionRequest) || !isOnEditorURL) { // Throw error return; } From d820e5df4b9afebd5cf7bcefd6339cbeda742a22 Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Wed, 13 Mar 2024 10:49:26 +0530 Subject: [PATCH 18/25] chore: Remove deprecated API uses in SecurityConfig (#31310) These APIs are getting deprecated and are setting up for removal soon. This PR changes such API uses to ones that aren't deprecated. This is needed towards upgrading Spring to get rid of a few CVEs on Appsmith image. --- .../server/configurations/SecurityConfig.java | 125 ++++++++---------- 1 file changed, 56 insertions(+), 69 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java index 0c96f2ec11..cc30de4dce 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java @@ -115,12 +115,10 @@ public class SecurityConfig { * hence using RouterFunctions to implement this feature. *

* Future folks: Please check out links: - * - https://www.baeldung.com/spring-webflux-static-content - * - https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-config-static-resources + * - ... + * - ... * - Class ResourceHandlerRegistry * for details. If you figure out a cleaner approach, please modify this function - * - * @return */ @Bean public RouterFunction publicRouter() { @@ -136,8 +134,7 @@ public class SecurityConfig { @Bean public SecurityWebFilterChain internalWebFilterChain(ServerHttpSecurity http) { return http.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/actuator/**")) - .httpBasic() - .authenticationManager(authentication -> { + .httpBasic(httpBasicSpec -> httpBasicSpec.authenticationManager(authentication -> { if (INTERNAL_PASSWORD.equals(authentication.getCredentials().toString())) { return Mono.just(UsernamePasswordAuthenticationToken.authenticated( authentication.getPrincipal(), @@ -147,79 +144,72 @@ public class SecurityConfig { return Mono.just(UsernamePasswordAuthenticationToken.unauthenticated( authentication.getPrincipal(), authentication.getCredentials())); } - }) - .and() - .authorizeExchange() - .anyExchange() - .hasAnyAuthority(INTERNAL) - .and() + })) + .authorizeExchange(authorizeExchangeSpec -> + authorizeExchangeSpec.anyExchange().hasAnyAuthority(INTERNAL)) .build(); } @Bean + @SuppressWarnings("Convert2MethodRef") // Helps readability. public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { ServerAuthenticationEntryPointFailureHandler failureHandler = new ServerAuthenticationEntryPointFailureHandler(authenticationEntryPoint); return http // The native CSRF solution doesn't work with WebFlux, yet, but only for WebMVC. So we make our own. - .csrf() - .disable() + .csrf(csrfSpec -> csrfSpec.disable()) .addFilterAt(new CSRFFilter(), SecurityWebFiltersOrder.CSRF) // Default security headers configuration from // https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/headers.html - .headers() - // Disabled here because add it in NGINX instead. - .contentTypeOptions() - .disable() - // Disabled because we use CSP's `frame-ancestors` instead. - .frameOptions() - .disable() - .and() - .anonymous() - .principal(createAnonymousUser()) - .and() + .headers(headerSpec -> headerSpec + // Disabled here because add it in Caddy instead. + .contentTypeOptions(options -> options.disable()) + // Disabled because we use CSP's `frame-ancestors` instead. + .frameOptions(options -> options.disable())) + .anonymous(anonymousSpec -> anonymousSpec.principal(createAnonymousUser())) // This returns 401 unauthorized for all requests that are not authenticated but authentication is // required // The client will redirect to the login page if we return 401 as Http status response - .exceptionHandling() - .authenticationEntryPoint(authenticationEntryPoint) - .accessDeniedHandler(accessDeniedHandler) - .and() - .authorizeExchange() - .matchers( - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, Url.LOGIN_URL), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, Url.HEALTH_CHECK), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL + "/super"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL + "/forgotPassword"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/verifyPasswordResetToken"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, USER_URL + "/resetPassword"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/invite/verify"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, USER_URL + "/invite/confirm"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/me"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/features"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, ASSET_URL + "/*"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, ACTION_URL + "/**"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, ACTION_COLLECTION_URL + "/view"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, PAGE_URL + "/**"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, APPLICATION_URL + "/**"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, THEME_URL + "/**"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, ACTION_URL + "/execute"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, TENANT_URL + "/current"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USAGE_PULSE_URL), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, CUSTOM_JS_LIB_URL + "/*/view"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL + "/resendEmailVerification"), - ServerWebExchangeMatchers.pathMatchers( - HttpMethod.POST, USER_URL + "/verifyEmailVerificationToken"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, PRODUCT_ALERT + "/alert"), - ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, CONSOLIDATED_API_URL + "/view")) - .permitAll() - .pathMatchers("/public/**", "/oauth2/**") - .permitAll() - .anyExchange() - .authenticated() - .and() + .exceptionHandling(exceptionHandlingSpec -> exceptionHandlingSpec + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler)) + .authorizeExchange(authorizeExchangeSpec -> authorizeExchangeSpec + // The following endpoints are allowed to be accessed without authentication + .matchers( + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, Url.LOGIN_URL), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, Url.HEALTH_CHECK), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL + "/super"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USER_URL + "/forgotPassword"), + ServerWebExchangeMatchers.pathMatchers( + HttpMethod.GET, USER_URL + "/verifyPasswordResetToken"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, USER_URL + "/resetPassword"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/invite/verify"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, USER_URL + "/invite/confirm"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/me"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, USER_URL + "/features"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, ASSET_URL + "/*"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, ACTION_URL + "/**"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, ACTION_COLLECTION_URL + "/view"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, PAGE_URL + "/**"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, APPLICATION_URL + "/**"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, THEME_URL + "/**"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, ACTION_URL + "/execute"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, TENANT_URL + "/current"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, USAGE_PULSE_URL), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, CUSTOM_JS_LIB_URL + "/*/view"), + ServerWebExchangeMatchers.pathMatchers( + HttpMethod.POST, USER_URL + "/resendEmailVerification"), + ServerWebExchangeMatchers.pathMatchers( + HttpMethod.POST, USER_URL + "/verifyEmailVerificationToken"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, PRODUCT_ALERT + "/alert"), + ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, CONSOLIDATED_API_URL + "/view")) + .permitAll() + .pathMatchers("/public/**", "/oauth2/**") + .permitAll() + .anyExchange() + .authenticated()) // Add Pre Auth rate limit filter before authentication filter .addFilterBefore( new ConditionalFilter(new PreAuth(rateLimitService), Url.LOGIN_URL), @@ -245,17 +235,14 @@ public class SecurityConfig { .authenticationSuccessHandler(authenticationSuccessHandler) .authenticationFailureHandler(authenticationFailureHandler) .authorizedClientRepository(new ClientUserRepository(userService, commonConfig))) - .logout() - .logoutUrl(Url.LOGOUT_URL) - .logoutSuccessHandler(new LogoutSuccessHandler(objectMapper, analyticsService)) - .and() + .logout(logoutSpec -> logoutSpec + .logoutUrl(Url.LOGOUT_URL) + .logoutSuccessHandler(new LogoutSuccessHandler(objectMapper, analyticsService))) .build(); } /** * This bean configures the parameters that need to be set when a Cookie is created for a logged in user - * - * @return */ @Bean public WebSessionIdResolver webSessionIdResolver() { From 65f7bfcc97f231335d28e64b41c9c78ae6c834b9 Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Wed, 13 Mar 2024 11:05:22 +0530 Subject: [PATCH 19/25] chore: Move Application repo to Bridge API (#31684) --- .../ce/BaseAppsmithRepositoryCEImpl.java | 5 ++ .../ce/CustomApplicationRepositoryCEImpl.java | 57 +++++-------------- 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java index 3eda9b1f9c..86360a1b1d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java @@ -131,6 +131,11 @@ public abstract class BaseAppsmithRepositoryCEImpl { .is(permission.getValue())); } + /** + * @deprecated Consider using {@code queryBuilder().byId(id)} or {@code Bridge.equal(BaseDomain.Fields.id, id)} + * instead. + */ + @Deprecated(forRemoval = true) protected Criteria getIdCriteria(Object id) { return where("id").is(id); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java index ae5d19326f..f2cda6e8f1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java @@ -1,11 +1,11 @@ package com.appsmith.server.repositories.ce; -import com.appsmith.external.models.BaseDomain; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationPage; import com.appsmith.server.domains.User; import com.appsmith.server.helpers.ce.bridge.Bridge; +import com.appsmith.server.helpers.ce.bridge.BridgeQuery; import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl; import com.appsmith.server.repositories.CacheableRepositoryHelper; import com.appsmith.server.solutions.ApplicationPermission; @@ -15,7 +15,6 @@ import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.convert.MongoConverter; -import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Update; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.util.StringUtils; @@ -26,8 +25,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import static org.springframework.data.mongodb.core.query.Criteria.where; - @Slf4j public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImpl implements CustomApplicationRepositoryCE { @@ -46,11 +43,6 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp this.applicationPermission = applicationPermission; } - @Override - protected Criteria getIdCriteria(Object id) { - return where(Application.Fields.id).is(id); - } - @Override public Mono findByIdAndWorkspaceId(String id, String workspaceId, AclPermission permission) { return queryBuilder() @@ -78,9 +70,8 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp @Override public Flux findByMultipleWorkspaceIds(Set workspaceIds, AclPermission permission) { - Criteria workspaceIdCriteria = where(Application.Fields.workspaceId).in(workspaceIds); return queryBuilder() - .criteria(workspaceIdCriteria) + .criteria(Bridge.in(Application.Fields.workspaceId, workspaceIds)) .permission(permission) .all(); } @@ -249,18 +240,11 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp @Override public Flux getAllApplicationIdsInWorkspaceAccessibleToARoleWithPermission( String workspaceId, AclPermission permission, String permissionGroupId) { - Criteria workspaceIdCriteria = - Criteria.where(Application.Fields.workspaceId).is(workspaceId); - - // Check if the permission is being provided by the given permission group - Criteria permissionGroupCriteria = Criteria.where(BaseDomain.Fields.policies) - .elemMatch(Criteria.where("permissionGroups") - .in(permissionGroupId) - .and("permission") - .is(permission.getValue())); - return queryBuilder() - .criteria(workspaceIdCriteria, permissionGroupCriteria) + .criteria(Bridge.equal(Application.Fields.workspaceId, workspaceId)) + // Check if the permission is being provided by the given permission group + .permission(permission) + .permissionGroups(Set.of(permissionGroupId)) .fields(Application.Fields.id) .all() .map(application -> application.getId()); @@ -269,14 +253,10 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp @Override public Mono getAllApplicationsCountAccessibleToARoleWithPermission( AclPermission permission, String permissionGroupId) { - - Criteria permissionGroupCriteria = Criteria.where(BaseDomain.Fields.policies) - .elemMatch(Criteria.where("permissionGroups") - .in(permissionGroupId) - .and("permission") - .is(permission.getValue())); - - return queryBuilder().criteria(permissionGroupCriteria).count(); + return queryBuilder() + .permission(permission) + .permissionGroups(Set.of(permissionGroupId)) + .count(); } @Override @@ -301,19 +281,12 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp @Override public Mono protectBranchedApplications( String applicationId, List branchNames, AclPermission permission) { - String isProtectedFieldPath = Application.Fields.gitApplicationMetadata_isProtectedBranch; + final BridgeQuery q = Bridge.equal( + Application.Fields.gitApplicationMetadata_defaultApplicationId, applicationId) + .in(Application.Fields.gitApplicationMetadata_branchName, branchNames); - String branchNameFieldPath = Application.Fields.gitApplicationMetadata_branchName; + Update setProtected = new Update().set(Application.Fields.gitApplicationMetadata_isProtectedBranch, true); - Criteria defaultApplicationIdCriteria = Criteria.where( - Application.Fields.gitApplicationMetadata_defaultApplicationId) - .is(applicationId); - Criteria branchMatchCriteria = Criteria.where(branchNameFieldPath).in(branchNames); - Update setProtected = new Update().set(isProtectedFieldPath, true); - - return queryBuilder() - .criteria(defaultApplicationIdCriteria, branchMatchCriteria) - .permission(permission) - .updateAll(setProtected); + return queryBuilder().criteria(q).permission(permission).updateAll(setProtected); } } From eabb046eb195f78f6583cc601bdadfa984999fe6 Mon Sep 17 00:00:00 2001 From: Vinay Chilukuri <101088862+vinay-appsmith@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:06:54 +0530 Subject: [PATCH 20/25] fix: Copy change in side-by-side announcement modal (#31703) Added punctuation and rewrote the message to make it crisper. ## Summary by CodeRabbit - **Documentation** - Updated text content for the split pane feature to enhance clarity and guide users more effectively. --- app/client/src/ce/constants/messages.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 3867df4500..9a8ea0143d 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -2460,7 +2460,7 @@ export const MAXIMIZE_BUTTON_TOOLTIP = () => `Expand code editor to full-screen`; export const MINIMIZE_BUTTON_TOOLTIP = () => `Open code editor next to the UI`; export const SPLITPANE_ANNOUNCEMENT = { - TITLE: () => "Code and UI side-by-side", + TITLE: () => "Code and UI, side-by-side", DESCRIPTION: () => - "You can now write queries & JS functions as you refer to your UI on the side. This is a beta version that we will continue to improve with your feedback.", + "Write queries and JS functions while you refer to the UI on the side! This is a beta version that we will continue to improve with your feedback.", }; From 32640eea0b1ce9a00ae7380553f49b1ae6bdae0d Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Wed, 13 Mar 2024 11:08:44 +0530 Subject: [PATCH 21/25] fix: NPE in LoginRateLimitFilter (#31687) We get an NPE when there's a request to the login API endpoint, with a missing `username` field. This PR fixes that. --- .../com/appsmith/server/configurations/SecurityConfig.java | 4 ++-- .../filters/{PreAuth.java => LoginRateLimitFilter.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename app/server/appsmith-server/src/main/java/com/appsmith/server/filters/{PreAuth.java => LoginRateLimitFilter.java} (92%) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java index cc30de4dce..50c430ccba 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java @@ -9,7 +9,7 @@ import com.appsmith.server.constants.Url; import com.appsmith.server.domains.User; import com.appsmith.server.filters.CSRFFilter; import com.appsmith.server.filters.ConditionalFilter; -import com.appsmith.server.filters.PreAuth; +import com.appsmith.server.filters.LoginRateLimitFilter; import com.appsmith.server.helpers.RedirectHelper; import com.appsmith.server.ratelimiting.RateLimitService; import com.appsmith.server.services.AnalyticsService; @@ -212,7 +212,7 @@ public class SecurityConfig { .authenticated()) // Add Pre Auth rate limit filter before authentication filter .addFilterBefore( - new ConditionalFilter(new PreAuth(rateLimitService), Url.LOGIN_URL), + new ConditionalFilter(new LoginRateLimitFilter(rateLimitService), Url.LOGIN_URL), SecurityWebFiltersOrder.FORM_LOGIN) .httpBasic(httpBasicSpec -> httpBasicSpec.authenticationFailureHandler(failureHandler)) .formLogin(formLoginSpec -> formLoginSpec diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/filters/PreAuth.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/filters/LoginRateLimitFilter.java similarity index 92% rename from app/server/appsmith-server/src/main/java/com/appsmith/server/filters/PreAuth.java rename to app/server/appsmith-server/src/main/java/com/appsmith/server/filters/LoginRateLimitFilter.java index ccaceda3d8..d64ca5d820 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/filters/PreAuth.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/filters/LoginRateLimitFilter.java @@ -18,12 +18,12 @@ import java.nio.charset.StandardCharsets; import static java.lang.Boolean.FALSE; @Slf4j -public class PreAuth implements WebFilter { +public class LoginRateLimitFilter implements WebFilter { private final ServerRedirectStrategy redirectStrategy = new DefaultServerRedirectStrategy(); private final RateLimitService rateLimitService; - public PreAuth(RateLimitService rateLimitService) { + public LoginRateLimitFilter(RateLimitService rateLimitService) { this.rateLimitService = rateLimitService; } @@ -52,7 +52,7 @@ public class PreAuth implements WebFilter { private Mono getUsername(ServerWebExchange exchange) { return exchange.getFormData() - .map(formData -> formData.getFirst(FieldName.USERNAME.toString())) + .mapNotNull(formData -> formData.getFirst(FieldName.USERNAME.toString())) .defaultIfEmpty(""); } From 0d206ebfbd46e6a0fefbd11292728c964f98599f Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Wed, 13 Mar 2024 11:11:12 +0530 Subject: [PATCH 22/25] chore: Migrate NewPageRepositoryCEImpl to use Bridge APIs (#31693) --- .../server/helpers/ce/bridge/BridgeQuery.java | 8 -- .../ce/CustomNewPageRepositoryCEImpl.java | 126 +++++++----------- 2 files changed, 47 insertions(+), 87 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java index 629b8ca03f..643c98b003 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/bridge/BridgeQuery.java @@ -88,14 +88,6 @@ public final class BridgeQuery extends Criteria { return this; } - /** - * Please use {@code Bridge.or} instead. This API looks and reads very confusing and unintuitive, so is explicitly - * disabled. - */ - public BridgeQuery or(BridgeQuery ignoredUnused) { - throw new UnsupportedOperationException("Not supported"); - } - public BridgeQuery and(BridgeQuery item) { checks.add(new Criteria().andOperator(item)); return this; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java index dbd43248ca..ea028ac40d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java @@ -3,8 +3,11 @@ package com.appsmith.server.repositories.ce; import com.appsmith.external.models.BranchAwareDomain; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewPage; import com.appsmith.server.dtos.PageDTO; +import com.appsmith.server.helpers.ce.bridge.Bridge; +import com.appsmith.server.helpers.ce.bridge.BridgeQuery; import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl; import com.appsmith.server.repositories.CacheableRepositoryHelper; import lombok.extern.slf4j.Slf4j; @@ -19,7 +22,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -44,44 +46,35 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl findByApplicationId(String applicationId, AclPermission aclPermission) { - Criteria applicationIdCriteria = where(NewPage.Fields.applicationId).is(applicationId); return queryBuilder() - .criteria(applicationIdCriteria) + .criteria(Bridge.equal(NewPage.Fields.applicationId, applicationId)) .permission(aclPermission) .all(); } @Override public Flux findByApplicationId(String applicationId, Optional permission) { - Criteria applicationIdCriteria = where(NewPage.Fields.applicationId).is(applicationId); return queryBuilder() - .criteria(applicationIdCriteria) + .criteria(Bridge.equal(NewPage.Fields.applicationId, applicationId)) .permission(permission.orElse(null)) .all(); } @Override public Flux findByApplicationIdAndNonDeletedEditMode(String applicationId, AclPermission aclPermission) { - Criteria applicationIdCriteria = where(NewPage.Fields.applicationId).is(applicationId); - // In case a page has been deleted in edit mode, but still exists in deployed mode, NewPage object would exist. - // To handle this, only fetch non-deleted pages - Criteria activeEditModeCriteria = - where(NewPage.Fields.unpublishedPage_deletedAt).is(null); - return queryBuilder() - .criteria(applicationIdCriteria, activeEditModeCriteria) - .permission(aclPermission) - .all(); + BridgeQuery q = Bridge.equal(NewPage.Fields.applicationId, applicationId) + // In case a page has been deleted in edit mode, but still exists in deployed mode, NewPage object would + // exist. To handle this, only fetch non-deleted pages + .isNull(NewPage.Fields.unpublishedPage_deletedAt); + return queryBuilder().criteria(q).permission(aclPermission).all(); } @Override public Mono findByIdAndLayoutsIdAndViewMode( String id, String layoutId, AclPermission aclPermission, Boolean viewMode) { - String layoutsIdKey; - String layoutsKey; + final String layoutsKey; - List criteria = new ArrayList<>(); - Criteria idCriterion = getIdCriteria(id); - criteria.add(idCriterion); + final BridgeQuery q = Bridge.equal(NewPage.Fields.id, id); if (Boolean.TRUE.equals(viewMode)) { layoutsKey = NewPage.Fields.publishedPage_layouts; @@ -90,58 +83,39 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl findByNameAndViewMode(String name, AclPermission aclPermission, Boolean viewMode) { - - List criteria = new ArrayList<>(); - - Criteria nameCriterion = getNameCriterion(name, viewMode); - criteria.add(nameCriterion); + final BridgeQuery q = getNameCriterion(name, viewMode); if (Boolean.FALSE.equals(viewMode)) { // In case a page has been deleted in edit mode, but still exists in deployed mode, NewPage object would // exist. To handle this, only fetch non-deleted pages - Criteria deletedCriterion = - where(NewPage.Fields.unpublishedPage_deletedAt).is(null); - criteria.add(deletedCriterion); + q.isNull(NewPage.Fields.unpublishedPage_deletedAt); } - return queryBuilder().criteria(criteria).permission(aclPermission).one(); + return queryBuilder().criteria(q).permission(aclPermission).one(); } @Override public Mono findByNameAndApplicationIdAndViewMode( String name, String applicationId, AclPermission aclPermission, Boolean viewMode) { - - List criteria = new ArrayList<>(); - - Criteria nameCriterion = getNameCriterion(name, viewMode); - criteria.add(nameCriterion); - - Criteria applicationIdCriterion = where(NewPage.Fields.applicationId).is(applicationId); - criteria.add(applicationIdCriterion); + BridgeQuery q = getNameCriterion(name, viewMode).equal(NewPage.Fields.applicationId, applicationId); if (Boolean.FALSE.equals(viewMode)) { // In case a page has been deleted in edit mode, but still exists in deployed mode, NewPage object would // exist. To handle this, only fetch non-deleted pages - Criteria deletedCriteria = - where(NewPage.Fields.unpublishedPage_deletedAt).is(null); - criteria.add(deletedCriteria); + q.isNull(NewPage.Fields.unpublishedPage_deletedAt); } - return queryBuilder().criteria(criteria).permission(aclPermission).one(); + return queryBuilder().criteria(q).permission(aclPermission).one(); } @Override @@ -161,24 +135,17 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl getNameCriterion(String name, Boolean viewMode) { + return Bridge.equal( + Boolean.TRUE.equals(viewMode) ? NewPage.Fields.publishedPage_name : NewPage.Fields.unpublishedPage_name, + name); } @Override @@ -197,22 +164,18 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl findPageByBranchNameAndDefaultPageId( String branchName, String defaultPageId, AclPermission permission) { final String defaultResources = NewPage.Fields.defaultResources; - Criteria defaultPageIdCriteria = - where(defaultResources + "." + FieldName.PAGE_ID).is(defaultPageId); - Criteria branchCriteria = - where(defaultResources + "." + FieldName.BRANCH_NAME).is(branchName); - return queryBuilder() - .criteria(defaultPageIdCriteria, branchCriteria) - .permission(permission) - .one(); + final BridgeQuery q = + // defaultPageIdCriteria + Bridge.equal(defaultResources + "." + FieldName.PAGE_ID, defaultPageId) + // branchCriteria + .equal(defaultResources + "." + FieldName.BRANCH_NAME, branchName); + return queryBuilder().criteria(q).permission(permission).one(); } @Override public Flux findSlugsByApplicationIds(List applicationIds, AclPermission aclPermission) { - Criteria applicationIdCriteria = where(NewPage.Fields.applicationId).in(applicationIds); - return queryBuilder() - .criteria(applicationIdCriteria) + .criteria(Bridge.in(NewPage.Fields.applicationId, applicationIds)) .fields( NewPage.Fields.unpublishedPage_slug, NewPage.Fields.unpublishedPage_customSlug, @@ -233,13 +196,19 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl findByGitSyncIdAndDefaultApplicationId( String defaultApplicationId, String gitSyncId, Optional permission) { final String defaultResources = BranchAwareDomain.Fields.defaultResources; - Criteria defaultAppIdCriteria = - where(defaultResources + "." + FieldName.APPLICATION_ID).is(defaultApplicationId); - Criteria gitSyncIdCriteria = where(FieldName.GIT_SYNC_ID).is(gitSyncId); - return queryBuilder() - .criteria(defaultAppIdCriteria, gitSyncIdCriteria) - .permission(permission.orElse(null)) - .first(); + + // defaultAppIdCriteria + final BridgeQuery q = + Bridge.equal(defaultResources + "." + NewPage.Fields.applicationId, defaultApplicationId); + + if (gitSyncId != null) { + // gitSyncIdCriteria + q.equal(NewPage.Fields.gitSyncId, gitSyncId); + } else { + q.isNull(NewPage.Fields.gitSyncId); + } + + return queryBuilder().criteria(q).permission(permission.orElse(null)).first(); } @Override @@ -277,9 +246,8 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl findAllByApplicationIdsWithoutPermission( List applicationIds, List includeFields) { - Criteria applicationCriteria = Criteria.where(FieldName.APPLICATION_ID).in(applicationIds); return queryBuilder() - .criteria(applicationCriteria) + .criteria(Bridge.in(FieldName.APPLICATION_ID, applicationIds)) .fields(includeFields) .all(); } From be9b751539edbd88d4b4639287f7675b13e2bf4a Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Wed, 13 Mar 2024 11:11:36 +0530 Subject: [PATCH 23/25] chore: Refactoring code to show plugin based icons for module instances on EE (#31713) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Refactoring code to show plugin based icons for module instances on EE Fixes [#30163](https://github.com/appsmithorg/appsmith/issues/30163) ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `897cc28f1c8d15efb7789788aba89687b85a4916` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **New Features** - Introduced a new interface for module metadata, including properties like module and plugin identifiers. - Added a new type property to the Module interface to distinguish module types. - Enhanced resource list loading with unique identifiers for each resource. - Implemented functionality to dynamically resolve and display icons based on module or plugin properties. - **Enhancements** - Updated the applications page to support workspaces more effectively, including active workspace identification. - Improved module selection and display across the application, allowing for a more integrated module management experience. - **Refactor** - Removed unused functions and components related to module icon resolution. - Streamlined the logic for fetching and displaying module-related information, including in action selectors and query editors. - **Bug Fixes** - Fixed an issue with resource object identification by introducing unique `id` fields. - **Style** - Added new class selector for module instance name editing, enhancing the styling options. --- .../src/ce/constants/ModuleConstants.ts | 12 ++++- .../ce/constants/ModuleInstanceConstants.ts | 1 + .../pages/Applications/ResourceListLoader.tsx | 2 +- .../src/ce/pages/Applications/index.tsx | 31 ++++++------ .../src/ce/selectors/modulesSelector.ts | 7 +++ .../ActionCreator/helpers.tsx | 31 ++++++------ .../useSource/useConnectToOptions.tsx | 27 +++++++--- .../ActionSelectorControl.tsx | 3 ++ .../components/utils/NameEditorComponent.tsx | 2 +- .../src/ee/selectors/modulesSelector.ts | 1 + .../src/pages/Editor/APIEditor/index.tsx | 12 ++++- .../pages/Editor/Explorer/ExplorerIcons.tsx | 18 ------- .../src/pages/Editor/QueryEditor/index.tsx | 17 ++++++- .../src/pages/Editor/{utils.ts => utils.tsx} | 49 ++++++++++++++++++- 14 files changed, 149 insertions(+), 64 deletions(-) create mode 100644 app/client/src/ce/selectors/modulesSelector.ts create mode 100644 app/client/src/ee/selectors/modulesSelector.ts rename app/client/src/pages/Editor/{utils.ts => utils.tsx} (88%) diff --git a/app/client/src/ce/constants/ModuleConstants.ts b/app/client/src/ce/constants/ModuleConstants.ts index 7cb873c206..856db60531 100644 --- a/app/client/src/ce/constants/ModuleConstants.ts +++ b/app/client/src/ce/constants/ModuleConstants.ts @@ -1,3 +1,5 @@ +import type { PluginType } from "entities/Action"; + type ID = string; export enum MODULE_TYPE { @@ -15,9 +17,17 @@ export interface ModuleInputSection { children?: ModuleInput[]; } -export interface Module { +export interface Module extends ModuleMetadata { id: ID; name: string; packageId: ID; inputsForm: ModuleInputSection[]; + type: MODULE_TYPE; +} + +export interface ModuleMetadata { + moduleId: string; + datasourceId?: string; + pluginId: string; + pluginType: PluginType; } diff --git a/app/client/src/ce/constants/ModuleInstanceConstants.ts b/app/client/src/ce/constants/ModuleInstanceConstants.ts index 526b042b92..b5721d8497 100644 --- a/app/client/src/ce/constants/ModuleInstanceConstants.ts +++ b/app/client/src/ce/constants/ModuleInstanceConstants.ts @@ -15,6 +15,7 @@ export interface ModuleInstance { inputs: { [key: string]: string; }; + sourceModuleId: ModuleId; } export interface ModuleInstanceData { diff --git a/app/client/src/ce/pages/Applications/ResourceListLoader.tsx b/app/client/src/ce/pages/Applications/ResourceListLoader.tsx index 3007567db2..9d364b4ab8 100644 --- a/app/client/src/ce/pages/Applications/ResourceListLoader.tsx +++ b/app/client/src/ce/pages/Applications/ResourceListLoader.tsx @@ -14,7 +14,7 @@ interface ResourcesLoaderProps { const DEFAULT_BACKGROUND_COLOR = "#9747FF1A"; const DEFAULT_ICON = "book"; -const DEAFULT_RESOURCES = [{ name: "Default Resource" }]; +const DEAFULT_RESOURCES = [{ id: "default", name: "Default Resource" }]; function ResourceListLoader({ isMobile, resources }: ResourcesLoaderProps) { const resourcesToUse = resources?.length ? resources : DEAFULT_RESOURCES; diff --git a/app/client/src/ce/pages/Applications/index.tsx b/app/client/src/ce/pages/Applications/index.tsx index 140b7c20bb..9bf7751955 100644 --- a/app/client/src/ce/pages/Applications/index.tsx +++ b/app/client/src/ce/pages/Applications/index.tsx @@ -369,7 +369,6 @@ export function WorkspaceMenuItem({ isFetchingWorkspaces ? 100 : 22 } /* this is to avoid showing tooltip for loaders */ icon="group-2-line" - key={workspace?.id} onSelect={handleWorkspaceClick} selected={selected} text={workspace?.name} @@ -386,8 +385,8 @@ export const submitCreateWorkspaceForm = async (data: any, dispatch: any) => { export interface LeftPaneProps { isBannerVisible?: boolean; isFetchingWorkspaces: boolean; - workspaces: any; - activeWorkspaceId: string | undefined; + workspaces: Workspace[]; + activeWorkspaceId?: string; } export function LeftPane(props: LeftPaneProps) { @@ -395,7 +394,7 @@ export function LeftPane(props: LeftPaneProps) { activeWorkspaceId, isBannerVisible = false, isFetchingWorkspaces, - workspaces, + workspaces = [], } = props; const isMobile = useIsMobileDevice(); @@ -408,18 +407,14 @@ export function LeftPane(props: LeftPaneProps) { isFetchingWorkspaces={isFetchingWorkspaces} > - {workspaces && - workspaces.map( - (workspace: any) => - workspace && ( - - ), - )} + {workspaces.map((workspace) => ( + + ))} @@ -895,7 +890,9 @@ export const ApplictionsMainPage = (props: any) => { if (!isFetchingWorkspaces) { workspaces = fetchedWorkspaces; } else { - workspaces = loadingUserWorkspaces as any; + workspaces = loadingUserWorkspaces.map( + (loadingWorkspaces) => loadingWorkspaces.workspace, + ) as any; } const [activeWorkspaceId, setActiveWorkspaceId] = useState< diff --git a/app/client/src/ce/selectors/modulesSelector.ts b/app/client/src/ce/selectors/modulesSelector.ts new file mode 100644 index 0000000000..9ccc15fbf7 --- /dev/null +++ b/app/client/src/ce/selectors/modulesSelector.ts @@ -0,0 +1,7 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import type { AppState } from "@appsmith/reducers"; +import type { Module } from "@appsmith/constants/ModuleConstants"; + +export const getAllModules = ( + state: AppState, +): Record | any => {}; diff --git a/app/client/src/components/editorComponents/ActionCreator/helpers.tsx b/app/client/src/components/editorComponents/ActionCreator/helpers.tsx index d67db141bc..6b96ebc666 100644 --- a/app/client/src/components/editorComponents/ActionCreator/helpers.tsx +++ b/app/client/src/components/editorComponents/ActionCreator/helpers.tsx @@ -1,4 +1,3 @@ -import type { ReactNode } from "react"; import React from "react"; import { getFunctionNameFromJsObjectExpression, @@ -20,7 +19,7 @@ import { PluginType } from "entities/Action"; import type { JSAction, Variable } from "entities/JSCollection"; import keyBy from "lodash/keyBy"; import { getActionConfig } from "pages/Editor/Explorer/Actions/helpers"; -import { EntityIcon, JsFileIconV2 } from "pages/Editor/Explorer/ExplorerIcons"; +import { JsFileIconV2 } from "pages/Editor/Explorer/ExplorerIcons"; import { useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; import type { @@ -66,11 +65,13 @@ import { selectEvaluationVersion } from "@appsmith/selectors/applicationSelector import { isJSAction } from "@appsmith/workers/Evaluation/evaluationUtils"; import type { DataTreeEntity } from "entities/DataTree/dataTreeTypes"; import type { ModuleInstanceDataState } from "@appsmith/constants/ModuleInstanceConstants"; -import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants"; import { setShowCreateNewModal } from "actions/propertyPaneActions"; import { setIdeEditorViewMode } from "actions/ideActions"; import { EditorViewMode } from "@appsmith/entities/IDE/constants"; import { getIsSideBySideEnabled } from "selectors/ideSelectors"; +import { resolveIcon } from "pages/Editor/utils"; +import { getAllModules } from "@appsmith/selectors/modulesSelector"; +import type { Module } from "@appsmith/constants/ModuleConstants"; const actionList: { label: string; @@ -393,16 +394,6 @@ export function useModalDropdownList(handleClose: () => void) { return finalList; } -export const getModuleInstanceIcon = (type: MODULE_TYPE): ReactNode => { - if (type === MODULE_TYPE.QUERY || type === MODULE_TYPE.JS) { - return ( - - - - ); - } -}; - export function getApiQueriesAndJSActionOptionsWithChildren( pageId: string, plugins: any, @@ -412,6 +403,7 @@ export function getApiQueriesAndJSActionOptionsWithChildren( handleClose: () => void, queryModuleInstances: ModuleInstanceDataState, jsModuleInstances: ReturnType, + modules: Record, ) { // this function gets a list of all the queries/apis and attaches it to actionList getApiAndQueryOptions( @@ -420,6 +412,7 @@ export function getApiQueriesAndJSActionOptionsWithChildren( dispatch, handleClose, queryModuleInstances, + modules, ); // this function gets a list of all the JS Objects and attaches it to actionList @@ -434,6 +427,7 @@ function getApiAndQueryOptions( dispatch: any, handleClose: () => void, queryModuleInstances: ModuleInstanceDataState, + modules: Record, ) { const state = store.getState(); const isSideBySideEnabled = getIsSideBySideEnabled(state); @@ -499,12 +493,17 @@ function getApiAndQueryOptions( } as TreeDropdownOption); }); queryModuleInstances.forEach((instance) => { + const module = modules[instance.config.sourceModuleId]; (queryOptions.children as TreeDropdownOption[]).push({ label: instance.config.name, id: instance.config.id, value: instance.config.name, type: queryOptions.value, - icon: getModuleInstanceIcon(instance.config.type), + icon: resolveIcon({ + iconLocation: plugins[module.pluginId]?.iconLocation || "", + pluginType: module.pluginType, + moduleType: module.type, + }), } as TreeDropdownOption); }); } @@ -587,7 +586,7 @@ export function getJSOptions( id: jsModuleInstance.config.id, value: jsModuleInstance.name, type: jsOption.value, - icon: getModuleInstanceIcon(MODULE_TYPE.JS), + icon: JsFileIconV2(), } as unknown as TreeDropdownOption; (jsOption.children as unknown as TreeDropdownOption[]).push(jsObject); @@ -637,6 +636,7 @@ export function useApisQueriesAndJsActionOptions(handleClose: () => void) { getQueryModuleInstances, ) as unknown as ModuleInstanceDataState; const jsModuleInstancesData = useSelector(getJSModuleInstancesData); + const modules = useSelector(getAllModules); // this function gets all the Queries/API's/JS Objects and attaches it to actionList return getApiQueriesAndJSActionOptionsWithChildren( @@ -648,5 +648,6 @@ export function useApisQueriesAndJsActionOptions(handleClose: () => void) { handleClose, queryModuleInstances, jsModuleInstancesData, + modules, ); } diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx index 2a781f7329..ceb84035ed 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx @@ -18,8 +18,6 @@ import type { ActionData, ActionDataState, } from "@appsmith/reducers/entityReducers/actionsReducer"; -import { EntityIcon } from "pages/Editor/Explorer/ExplorerIcons"; -import { Icon } from "design-system"; import type { ModuleInstanceData, ModuleInstanceDataState, @@ -27,6 +25,11 @@ import type { import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; import type { AppState } from "@appsmith/reducers"; +import type { Module } from "@appsmith/constants/ModuleConstants"; +import { getAllModules } from "@appsmith/selectors/modulesSelector"; +import { resolveIcon } from "pages/Editor/utils"; +import { Icon } from "design-system"; +import { EntityIcon } from "pages/Editor/Explorer/ExplorerIcons"; enum SortingWeights { alphabetical = 1, @@ -97,12 +100,23 @@ interface ConnectToOptionsProps { export const getQueryIcon = ( query: ActionData | ModuleInstanceData, pluginImages: Record, + modules: Record, ) => { if (query.config.hasOwnProperty("type")) { + const q = query as ModuleInstanceData; + const module = modules[q.config.sourceModuleId]; + const icon = resolveIcon({ + iconLocation: pluginImages[module.pluginId] || "", + pluginType: module.pluginType, + moduleType: module.type, + }); + return ( - - - + icon || ( + + + + ) ); } else { const action = query as ActionData; @@ -172,6 +186,7 @@ function useConnectToOptions(props: ConnectToOptionsProps) { const { pluginImages, widget } = props; const queryModuleInstances = useSelector(getQueryModuleInstances); + const modules = useSelector(getAllModules); let filteredQueries: ActionData[] | ModuleInstanceData[] = queries; /* Exclude Gsheets from query options till this gets resolved https://github.com/appsmithorg/appsmith/issues/27102*/ @@ -193,7 +208,7 @@ function useConnectToOptions(props: ConnectToOptionsProps) { id: query.config.id, label: query.config.name, value: getBindingValue(widget, query), - icon: getQueryIcon(query, pluginImages), + icon: getQueryIcon(query, pluginImages, modules), onSelect: function (value?: string, valueOption?: DropdownOptionType) { addBinding( valueOption?.value, diff --git a/app/client/src/components/propertyControls/ActionSelectorControl.tsx b/app/client/src/components/propertyControls/ActionSelectorControl.tsx index 9ee92ede1f..ef4a73e6ac 100644 --- a/app/client/src/components/propertyControls/ActionSelectorControl.tsx +++ b/app/client/src/components/propertyControls/ActionSelectorControl.tsx @@ -32,6 +32,7 @@ import type { } from "@appsmith/constants/ModuleInstanceConstants"; import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants"; import type { JSAction } from "entities/JSCollection"; +import { getAllModules } from "@appsmith/selectors/modulesSelector"; class ActionSelectorControl extends BaseControl { componentRef = React.createRef(); @@ -108,6 +109,7 @@ class ActionSelectorControl extends BaseControl { const moduleInstances = getModuleInstances(state); const queryModuleInstances = [] as ModuleInstanceDataState; const jsModuleInstances = getJSModuleInstancesData(state); + const modules = getAllModules(state); if (!!moduleInstances) { for (const moduleInstance of Object.values(moduleInstances)) { @@ -166,6 +168,7 @@ class ActionSelectorControl extends BaseControl { }, queryModuleInstances, jsModuleInstances, + modules, ); try { diff --git a/app/client/src/components/utils/NameEditorComponent.tsx b/app/client/src/components/utils/NameEditorComponent.tsx index 9156cef65d..47c55d5e8a 100644 --- a/app/client/src/components/utils/NameEditorComponent.tsx +++ b/app/client/src/components/utils/NameEditorComponent.tsx @@ -34,7 +34,7 @@ export const NameWrapper = styled.div<{ enableFontStyling?: boolean }>` }` : null} - & .t--action-name-edit-field, & .t--js-action-name-edit-field { + & .t--action-name-edit-field, & .t--js-action-name-edit-field, & .t--module-instance-name-edit-field { width: 100%; & > span { diff --git a/app/client/src/ee/selectors/modulesSelector.ts b/app/client/src/ee/selectors/modulesSelector.ts new file mode 100644 index 0000000000..cbfc9be79f --- /dev/null +++ b/app/client/src/ee/selectors/modulesSelector.ts @@ -0,0 +1 @@ +export * from "ce/selectors/modulesSelector"; diff --git a/app/client/src/pages/Editor/APIEditor/index.tsx b/app/client/src/pages/Editor/APIEditor/index.tsx index 953ef66b0b..90d7a519a3 100644 --- a/app/client/src/pages/Editor/APIEditor/index.tsx +++ b/app/client/src/pages/Editor/APIEditor/index.tsx @@ -28,7 +28,7 @@ import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { ApiEditorContextProvider } from "./ApiEditorContext"; import type { PaginationField } from "api/ActionAPI"; -import { get } from "lodash"; +import { get, keyBy } from "lodash"; import PerformanceTracker, { PerformanceTransactionName, } from "utils/PerformanceTracker"; @@ -38,6 +38,8 @@ import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants"; import Disabler from "pages/common/Disabler"; import ConvertEntityNotification from "@appsmith/pages/common/ConvertEntityNotification"; import { useIsEditorPaneSegmentsEnabled } from "../IDE/hooks"; +import { Icon } from "design-system"; +import { resolveIcon } from "../utils"; type ApiEditorWrapperProps = RouteComponentProps; @@ -65,6 +67,12 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) { const isConverting = useSelector((state) => getIsActionConverting(state, action?.id || ""), ); + const pluginGroups = useMemo(() => keyBy(plugins, "id"), [plugins]); + const icon = resolveIcon({ + iconLocation: pluginGroups[pluginId]?.iconLocation || "", + pluginType: action?.pluginType || "", + moduleType: action?.actionConfiguration?.body?.moduleType, + }) || ; const isChangePermitted = getHasManageActionPermission( isFeatureEnabled, @@ -150,7 +158,7 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) { const notification = useMemo(() => { if (!isConverting) return null; - return ; + return ; }, [action?.name, isConverting]); return ( diff --git a/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx b/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx index 848b38974b..e1c760a333 100644 --- a/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx +++ b/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx @@ -337,21 +337,3 @@ export function AppsmithAIIcon() { export function ActionUrlIcon(url: string) { return ; } - -export function ModuleIcon( - height = 18, - width = 18, - noBackground = false, - noBorder = false, -) { - return ( - - - - ); -} diff --git a/app/client/src/pages/Editor/QueryEditor/index.tsx b/app/client/src/pages/Editor/QueryEditor/index.tsx index 9b593f6a72..e7c90460a7 100644 --- a/app/client/src/pages/Editor/QueryEditor/index.tsx +++ b/app/client/src/pages/Editor/QueryEditor/index.tsx @@ -19,6 +19,7 @@ import { DatasourceCreateEntryPoints } from "constants/Datasource"; import { getAction, getIsActionConverting, + getPluginImages, getPluginSettingConfigs, } from "@appsmith/selectors/entitiesSelector"; import { integrationEditorURL } from "@appsmith/RouteBuilder"; @@ -38,6 +39,8 @@ import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants"; import ConvertEntityNotification from "@appsmith/pages/common/ConvertEntityNotification"; import { PluginType } from "entities/Action"; import { useIsEditorPaneSegmentsEnabled } from "../IDE/hooks"; +import { Icon } from "design-system"; +import { resolveIcon } from "../utils"; type QueryEditorProps = RouteComponentProps; @@ -58,6 +61,12 @@ function QueryEditor(props: QueryEditorProps) { const isConverting = useSelector((state) => getIsActionConverting(state, actionId || ""), ); + const pluginImages = useSelector(getPluginImages); + const icon = resolveIcon({ + iconLocation: pluginImages[pluginId] || "", + pluginType: action?.pluginType || "", + moduleType: action?.actionConfiguration?.body?.moduleType, + }) || ; const isDeletePermitted = getHasDeleteActionPermission( isFeatureEnabled, @@ -156,7 +165,13 @@ function QueryEditor(props: QueryEditorProps) { const notification = useMemo(() => { if (!isConverting) return null; - return ; + return ( + + ); }, [action?.name, isConverting]); return ( diff --git a/app/client/src/pages/Editor/utils.ts b/app/client/src/pages/Editor/utils.tsx similarity index 88% rename from app/client/src/pages/Editor/utils.ts rename to app/client/src/pages/Editor/utils.tsx index 84529bad59..03597d3b22 100644 --- a/app/client/src/pages/Editor/utils.ts +++ b/app/client/src/pages/Editor/utils.tsx @@ -1,7 +1,8 @@ -import { debounce, random } from "lodash"; -import { useEffect, useMemo, useState } from "react"; +import React from "react"; import ReactDOM from "react-dom"; +import { useEffect, useMemo, useState } from "react"; import { useLocation } from "react-router"; +import { debounce, random } from "lodash"; import type { WidgetCardsGroupedByTags, WidgetTags, @@ -19,6 +20,15 @@ import { useSelector } from "react-redux"; import { getCurrentPageId } from "selectors/editorSelectors"; import type { WidgetCardProps } from "widgets/BaseWidget"; import type { ActionResponse } from "api/ActionAPI"; +import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants"; +import { + ENTITY_ICON_SIZE, + EntityIcon, + JsFileIconV2, + dbQueryIcon, +} from "pages/Editor/Explorer/ExplorerIcons"; +import { PluginType } from "entities/Action"; +import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; export const draggableElement = ( id: string, @@ -336,3 +346,38 @@ export const actionResponseDisplayDataFormats = ( responseDisplayFormat, }; }; + +function resolveQueryModuleIcon( + iconLocation: string, + pluginType: string, + isLargeIcon: boolean, +) { + if (iconLocation) + return ( + + entityIcon + + ); + else if (pluginType === PluginType.DB) return dbQueryIcon; +} + +export function resolveIcon({ + iconLocation, + isLargeIcon = false, + moduleType, + pluginType, +}: { + iconLocation: string; + pluginType: string; + moduleType: string; + isLargeIcon?: boolean; +}) { + if (moduleType === MODULE_TYPE.JS) { + return isLargeIcon ? JsFileIconV2(34, 34) : JsFileIconV2(16, 16); + } else { + return resolveQueryModuleIcon(iconLocation, pluginType, isLargeIcon); + } +} From eb828bba1d604befd4cc56a71054aa149f63a4bf Mon Sep 17 00:00:00 2001 From: ashit-rath Date: Wed, 13 Mar 2024 11:36:11 +0530 Subject: [PATCH 24/25] fix: api module inputs pane width (#31708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Fix Action right pane width which affects the inputs section in modules Fixes https://github.com/appsmithorg/appsmith/issues/31592 ## Automation /ok-to-test tags="@tag.IDE, @tag.Datasource,@tag.Sanity,@tag.Visual,@tag.Datasource, @tag.GSheet" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `69515d9cc1d1eba61a92e998a57c121d3a051272` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **Refactor** - Improved structure and styling of the sidebar component in the editor for better usability. - Reorganized editor form components for a more intuitive layout and navigation. - Simplified the editor's JSON to form conversion process for enhanced performance and maintainability. --- .../ActionRightPane/index.tsx | 33 ++- .../Editor/APIEditor/CommonEditorForm.tsx | 193 +++++++++--------- .../Editor/QueryEditor/EditorJSONtoForm.tsx | 51 +---- 3 files changed, 128 insertions(+), 149 deletions(-) diff --git a/app/client/src/components/editorComponents/ActionRightPane/index.tsx b/app/client/src/components/editorComponents/ActionRightPane/index.tsx index 7c6a68d857..386787d0eb 100644 --- a/app/client/src/components/editorComponents/ActionRightPane/index.tsx +++ b/app/client/src/components/editorComponents/ActionRightPane/index.tsx @@ -58,6 +58,17 @@ const SideBar = styled.div` } `; +const Wrapper = styled.div` + border-left: 1px solid var(--ads-v2-color-border); + padding: 0 var(--ads-v2-spaces-7) var(--ads-v2-spaces-4); + overflow: hidden; + border-bottom: 0; + display: flex; + width: ${(props) => props.theme.actionSidePane.width}px; + margin-top: 10px; + /* margin-left: var(--ads-v2-spaces-7); */ +`; + export function useEntityDependencies(actionName: string) { const deps = useSelector((state: AppState) => state.evaluations.dependencies); const entityDependencies = useMemo( @@ -90,16 +101,18 @@ function ActionSidebar({ } return ( - - {actionRightPaneBackLink} - - {additionalSections && ( - - {additionalSections} - - )} - - + + + {actionRightPaneBackLink} + + {additionalSections && ( + + {additionalSections} + + )} + + + ); } diff --git a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx index eacb7df5a0..303a162a62 100644 --- a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx +++ b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx @@ -644,102 +644,107 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { )} - - - - - - {Object.values(API_EDITOR_TABS).map((tab) => ( - - {createMessage(API_EDITOR_TAB_TITLES[tab])} - - ))} - - - - - - - - - - - - {props.bodyUIComponent} - - - {props.paginationUIComponent} - - - - - - - + + + + + + {Object.values(API_EDITOR_TABS).map((tab) => ( + + {createMessage(API_EDITOR_TAB_TITLES[tab])} + + ))} + + + + + - - - - - - + + + + + + + {props.bodyUIComponent} + + + {props.paginationUIComponent} + + + + + + + + + + + + + + ` - border-left: 1px solid var(--ads-v2-color-border); - padding: 0 var(--ads-v2-spaces-7) var(--ads-v2-spaces-4); - overflow: hidden; - border-bottom: 0; - display: ${(props) => (props.show ? "flex" : "none")}; - width: ${(props) => props.theme.actionSidePane.width}px; - margin-top: 10px; - /* margin-left: var(--ads-v2-spaces-7); */ -`; - export const SegmentedControlContainer = styled.div` padding: 0 var(--ads-v2-spaces-7); padding-top: var(--ads-v2-spaces-4); @@ -234,13 +215,6 @@ export function EditorJSONtoForm(props: Props) { FEATURE_FLAG.release_actions_redesign_enabled, ); - const showRightPane = Boolean(actionRightPaneAdditionSections); - - // get the current action's plugin name - const currentActionPluginName = useSelector((state: AppState) => - getPluginNameFromId(state, currentActionConfig?.pluginId || ""), - ); - const dispatch = useDispatch(); const handleDocumentationClick = () => { @@ -254,21 +228,12 @@ export function EditorJSONtoForm(props: Props) { id: currentActionConfig ? currentActionConfig.id : "", }; - const { hasDependencies } = useEntityDependencies(props.actionName); - const selectedConfigTab = useSelector(getQueryPaneConfigSelectedTabIndex); const setSelectedConfigTab = useCallback((selectedIndex: string) => { dispatch(setQueryPaneConfigSelectedTabIndex(selectedIndex)); }, []); - // here we check for normal conditions for opening action pane - // or if any of the flags are true, We should open the actionpane by default. - const shouldOpenActionPaneByDefault = - hasDependencies || - !!actionResponse || - currentActionPluginName !== PluginName.SMTP; - // when switching between different redux forms, make sure this redux form has been initialized before rendering anything. // the initialized prop below comes from redux-form. if (!props.initialized) { @@ -419,14 +384,10 @@ export function EditorJSONtoForm(props: Props) { /> - {showRightPane && ( - - - - )} + From e99cc39e47d6caa4bd8d2b10d447889d8232ac5f Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Wed, 13 Mar 2024 11:53:49 +0530 Subject: [PATCH 25/25] chore: Block Selections when Canvas is in Side by Side mode (#31587) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request aims to enhance the user experience within the application by modifying the canvas behavior when it is displayed in "Side by Side" mode alongside Queries or JavaScript sections. The key change is the disabling of direct selections on the canvas, allowing interactions with canvas elements only through cmd + click or by clicking on the widget's name. This adjustment is intended to facilitate a view-only mode for the canvas during Queries or JS editing, thereby improving layout and user interaction. Additionally, the PR introduces enhancements to the application's testing framework, focusing on improving test reliability in scenarios involving UI interaction and state changes. Notable updates include: - Improved error tooltip handling in CurrencyInput_spec.js. - Ensured page state saving before verifying element presence in Listv2_BasicChildWidgetInteraction_spec.js. - Replaced cy.wait("@updateLayout") with cy.assertPageSave() and introduced a delay in Listv2_spec.js to accommodate functionality changes. - Implemented visibility checks in TableV2_Button_Icon_validation_spec.js to prevent timing-related test failures. These technical updates collectively aim to bolster the application's testing framework, enhancing the reliability and accuracy of automated tests, especially in UI interaction and state change scenarios. #### PR fixes following issue(s) Fixes #30864 ## Automation /ok-to-test tags="@tag.Widget" > [!IMPORTANT] > Workflow run: > Commit: `15e1cf937a9d15adaea68e16a55006d993a07cbf` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **New Features** - Added new constants for widget selection and focus management. - Introduced a new event type for tracking widget selections in code mode. - **Tests** - Enhanced test assertions and interactions for better reliability and error handling in various widgets. - **Refactor** - Improved widget selection logic and URL handling for a more intuitive user experience. --- .../ClientSide/Widgets/ContainerTest2_spec.ts | 10 ++--- .../CurrencyInput/CurrencyInput_spec.js | 2 +- .../Widgets/ListV2/ListV2_NestedList_spec.ts | 1 + ...Listv2_BasicChildWidgetInteraction_spec.js | 14 +++---- .../ClientSide/Widgets/ListV2/Listv2_spec.js | 6 ++- .../TableV2_Button_Icon_validation_spec.js | 4 +- .../cypress/locators/commonlocators.json | 1 - app/client/src/actions/widgetActions.tsx | 17 +++++++- .../src/ce/constants/ReduxActionConstants.tsx | 2 + app/client/src/ce/utils/analyticsUtilTypes.ts | 3 +- .../common/draggable/DraggableComponent.tsx | 11 +++-- .../common/dropTarget/DropTargetComponent.tsx | 9 +++- .../common/resizer/ModalResizableLayer.tsx | 5 ++- .../common/resizer/ResizableComponent.tsx | 8 ++++ .../common/widgetName/SettingsControl.tsx | 32 +++++--------- .../CanvasSelectionArena.tsx | 3 ++ app/client/src/pages/Editor/Canvas.tsx | 31 +++++++------- .../src/pages/Editor/IDE/MainPane/index.tsx | 2 + app/client/src/pages/Editor/IDE/hooks.ts | 42 ++++++++++++++++++- .../Editor/WidgetsEditor/CodeModeTooltip.tsx | 36 ++++++++++++++++ .../reducers/uiReducers/dragResizeReducer.ts | 21 +++++++++- app/client/src/sagas/WidgetSelectionSagas.ts | 29 ++++++++++++- app/client/src/selectors/ui.tsx | 13 ++++++ .../src/selectors/widgetDragSelectors.ts | 6 ++- app/client/src/selectors/widgetSelectors.ts | 6 ++- .../utils/hooks/useAllowEditorDragToSelect.ts | 6 ++- .../src/utils/hooks/useWidgetSelection.ts | 8 +++- app/client/src/utils/storage.ts | 24 +++++++++++ .../header/actions/filter/FilterPane.tsx | 4 -- 29 files changed, 276 insertions(+), 80 deletions(-) create mode 100644 app/client/src/pages/Editor/WidgetsEditor/CodeModeTooltip.tsx diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts index 27c8963d7c..9045781906 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts @@ -5,7 +5,6 @@ import { locators, propPane, } from "../../../../support/Objects/ObjectsCore"; -import Canvas from "../../../../support/Pages/Canvas"; import EditorNavigation, { EntityType, PageLeftPane, @@ -94,12 +93,9 @@ describe( ); deployMode.NavigateBacktoEditor(); - // Verify multiple widgets selected groups into single container - Canvas.selectMultipleWidgets(["Input1", "Select1", "Text3"]); - agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{g}`); - agHelper.Sleep(1000); - PageLeftPane.assertPresence("Container3"); - entityExplorer.DeleteWidgetFromEntityExplorer("Container3"); + entityExplorer.DeleteWidgetFromEntityExplorer("Input1"); + entityExplorer.DeleteWidgetFromEntityExplorer("Select1"); + entityExplorer.DeleteWidgetFromEntityExplorer("Text3"); }); it("4. Validate visible toggle", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInput_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInput_spec.js index 221c984351..e9f9e34752 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInput_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInput_spec.js @@ -286,7 +286,7 @@ describe( //Should check that widget input is not showing any errors on input cy.get(widgetInput).type("123456789"); cy.focused().then(() => { - expect(Cypress.$(themelocators.popover)).not.to.exist; + cy.get(".error-tooltip .bp3-popover-content").should("not.exist"); }); }); }, diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts index 266064d28d..2ce68154fb 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts @@ -154,6 +154,7 @@ describe( it("5. Verify Theme change", () => { agHelper.PressEscape(); appSettings.OpenPaneAndChangeTheme("Pacific"); + agHelper.WaitUntilToastDisappear("Theme Pacific applied"); [0, 1, 2].forEach((index) => { agHelper.AssertAttribute( locators._listText, diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js index bcd2f9ecd9..7b9fae85d3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js @@ -11,6 +11,7 @@ const containerWidgetSelector = `[type="CONTAINER_WIDGET"]`; function dragAndDropToWidget(widgetType, destinationWidget, { x, y }) { const selector = `.t--widget-card-draggable-${widgetType}`; cy.wait(800); + PageLeftPane.switchToAddNew(); cy.get(selector) .first() .scrollIntoView() @@ -34,9 +35,9 @@ function deleteAllWidgetsInContainer() { force: true, }); cy.get("body").type(`{${modifierKey}}{a}`); - cy.get("body").type("{del}"); - cy.wait(200); + cy.get("body").type("{del}"); + cy.get(commonlocators.layoutControls).should("be.visible"); } function checkSelectedRadioValue(selector, value) { @@ -63,12 +64,13 @@ describe( x: 250, y: 50, }); + cy.assertPageSave(); // Verify drop cy.get(publishLocators.inputWidget).should("exist"); // Type value - cy.get(publishLocators.inputWidget).find("input").type("abcd"); + cy.get(publishLocators.inputWidget).find("input").first().type("abcd"); // Verify if the value got typed cy.get(publishLocators.inputWidget) @@ -78,7 +80,6 @@ describe( deleteAllWidgetsInContainer(); // Drop Select widget - PageLeftPane.switchToAddNew(); dragAndDropToWidget("selectwidget", "containerwidget", { x: 250, y: 50, @@ -115,7 +116,6 @@ describe( deleteAllWidgetsInContainer(); // Drop Checkbox widget - PageLeftPane.switchToAddNew(); dragAndDropToWidget("checkboxgroupwidget", "containerwidget", { x: 250, y: 50, @@ -158,7 +158,6 @@ describe( deleteAllWidgetsInContainer(); // Drop Switch widget - PageLeftPane.switchToAddNew(); dragAndDropToWidget("switchwidget", "containerwidget", { x: 250, y: 50, @@ -201,9 +200,8 @@ describe( _.deployMode.NavigateBacktoEditor(); deleteAllWidgetsInContainer(); - + cy.wait(800); // Drop Radio widget - PageLeftPane.switchToAddNew(); dragAndDropToWidget("radiogroupwidget", "containerwidget", { x: 250, y: 50, diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_spec.js index 4b0c2e1f6b..afebdc4abf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_spec.js @@ -68,7 +68,8 @@ describe( entityExplorer.DragDropWidgetNVerify(widget); //cy.dragAndDropToWidget(widget, "listwidgetv2", { x: 350, y: 50 }); agHelper.GetNClick(propPane._deleteWidget); - cy.wait("@updateLayout"); + cy.assertPageSave(); + cy.wait(800); }); }, ); @@ -88,7 +89,8 @@ describe( cy.assertPageSave(); cy.get(`.t--draggable-${widget}`).should("exist"); cy.get(widgetsPage.removeWidget).click({ force: true }); - cy.wait("@updateLayout"); + cy.assertPageSave(); + cy.wait(800); }); }, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js index 955087e218..83ba744fa2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js @@ -23,9 +23,9 @@ describe( //cy.createModal("Modal", this.dataSet.ModalName); cy.createModal("Modal", "onRowSelected"); cy.isSelectRow(1); - cy.get(".bp3-overlay-backdrop").click({ force: true }); + cy.get(".bp3-overlay-backdrop").last().click({ force: true }); cy.isSelectRow(2); - cy.get(".bp3-overlay-backdrop").click({ force: true }); + cy.get(".bp3-overlay-backdrop").last().click({ force: true }); }); it("2. Table widget V2 with button colour change validation", function () { diff --git a/app/client/cypress/locators/commonlocators.json b/app/client/cypress/locators/commonlocators.json index 7443ea1aaf..cd6f50d6e6 100644 --- a/app/client/cypress/locators/commonlocators.json +++ b/app/client/cypress/locators/commonlocators.json @@ -81,7 +81,6 @@ "evaluatedCurrentValue": "div:last-of-type .t--CodeEditor-evaluatedValue > div:last-of-type pre", "entityExplorersearch": "#entity-explorer-search", "saveStatusContainer": ".t--save-status-container", - "saveStatusIsSaving": "t--save-status-is-saving", "statusSaving": ".t--save-status-is-saving", "saveStatusError": ".t--save-status-error", "selectWidgetVirtualList": ".menu-virtual-list div", diff --git a/app/client/src/actions/widgetActions.tsx b/app/client/src/actions/widgetActions.tsx index b67ca7ef21..0d16591262 100644 --- a/app/client/src/actions/widgetActions.tsx +++ b/app/client/src/actions/widgetActions.tsx @@ -47,9 +47,15 @@ export const createModalAction = ( export const focusWidget = ( widgetId?: string, -): ReduxAction<{ widgetId?: string }> => ({ + alt?: boolean, +): ReduxAction<{ widgetId?: string; alt?: boolean }> => ({ type: ReduxActionTypes.FOCUS_WIDGET, - payload: { widgetId }, + payload: { widgetId, alt }, +}); + +export const altFocusWidget = (alt: boolean) => ({ + type: ReduxActionTypes.ALT_FOCUS_WIDGET, + payload: alt, }); export const showModal = (id: string, shouldSelectModal = true) => { @@ -144,3 +150,10 @@ export const partialExportWidgets = (params: PartialExportParams) => { payload: params, }; }; + +export const setWidgetSelectionBlock = (payload: boolean) => { + return { + type: ReduxActionTypes.SET_WIDGET_SELECTION_BLOCK, + payload, + }; +}; diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index 4077a4ad75..de8c869fad 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -917,6 +917,8 @@ const ActionTypes = { SET_API_PANE_DEBUGGER_STATE: "SET_API_PANE_DEBUGGER_STATE", SET_JS_PANE_DEBUGGER_STATE: "SET_JS_PANE_DEBUGGER_STATE", SET_CANVAS_DEBUGGER_STATE: "SET_CANVAS_DEBUGGER_STATE", + SET_WIDGET_SELECTION_BLOCK: "SET_WIDGET_SELECTION_BLOCK", + ALT_FOCUS_WIDGET: "ALT_FOCUS_WIDGET", }; export const ReduxActionTypes = { diff --git a/app/client/src/ce/utils/analyticsUtilTypes.ts b/app/client/src/ce/utils/analyticsUtilTypes.ts index 6fdfc40af1..2d4a0dd553 100644 --- a/app/client/src/ce/utils/analyticsUtilTypes.ts +++ b/app/client/src/ce/utils/analyticsUtilTypes.ts @@ -385,7 +385,8 @@ export type ONBOARDING_FLOW_EVENTS = | "ONBOARDING_FLOW_CLICK_SKIP_BUTTON_START_FROM_DATA_PAGE" | "ONBOARDING_FLOW_CLICK_SKIP_BUTTON_DATASOURCE_FORM_PAGE" | "ONBOARDING_FLOW_CLICK_SKIP_BUTTON_START_FROM_TEMPLATE_PAGE" - | "ONBOARDING_FLOW_CLICK_SKIP_BUTTON_TEMPLATE_DETAILS_PAGE"; + | "ONBOARDING_FLOW_CLICK_SKIP_BUTTON_TEMPLATE_DETAILS_PAGE" + | "CODE_MODE_WIDGET_SELECTION"; export type DATASOURCE_SCHEMA_EVENTS = | "DATASOURCE_SCHEMA_SEARCH" diff --git a/app/client/src/layoutSystems/common/draggable/DraggableComponent.tsx b/app/client/src/layoutSystems/common/draggable/DraggableComponent.tsx index 86d78353ef..05f4725940 100644 --- a/app/client/src/layoutSystems/common/draggable/DraggableComponent.tsx +++ b/app/client/src/layoutSystems/common/draggable/DraggableComponent.tsx @@ -20,13 +20,13 @@ import { getShouldAllowDrag } from "selectors/widgetDragSelectors"; import { combinedPreviewModeSelector } from "selectors/editorSelectors"; import { getAnvilSpaceDistributionStatus } from "layoutSystems/anvil/integrations/selectors"; -const DraggableWrapper = styled.div` +const DraggableWrapper = styled.div<{ draggable: boolean }>` display: block; flex-direction: column; width: 100%; height: 100%; user-select: none; - cursor: grab; + cursor: ${(props) => (props.draggable ? "grab" : "unset")}; `; export interface DraggableComponentProps { @@ -37,7 +37,7 @@ export interface DraggableComponentProps { type: string; children: ReactNode; generateDragState: ( - e: React.DragEvent, + e: React.DragEvent, draggableRef: HTMLElement, ) => SetDraggingStateActionPayload; dragDisabled: boolean; @@ -53,7 +53,6 @@ const WidgetBoundaries = styled.div` ${(props) => getColorWithOpacity(props.theme.colors.textAnchor, 0.5)}; pointer-events: none; top: 0; - position: absolute; left: 0; `; @@ -100,14 +99,14 @@ function DraggableComponent(props: DraggableComponentProps) { !props.isFlexChild && (isCurrentWidgetDragging || isDraggingSibling); // When mouse is over this draggable - const handleMouseOver = (e: any) => { + const handleMouseOver = (e: React.MouseEvent) => { focusWidget && !isResizingOrDragging && !isFocused && !isDistributingSpace && !props.resizeDisabled && !isPreviewMode && - focusWidget(props.widgetId); + focusWidget(props.widgetId, e.metaKey); e.stopPropagation(); }; diff --git a/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx index 9639be084c..846dc4c1a8 100644 --- a/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx +++ b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx @@ -40,6 +40,7 @@ import { useCurrentAppState } from "pages/Editor/IDE/hooks"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { getWidgetSelectionBlock } from "selectors/ui"; import { isAutoHeightEnabledForWidget, isAutoHeightEnabledForWidgetWithLimits, @@ -259,6 +260,7 @@ export function DropTargetComponent(props: DropTargetComponentProps) { ); // Are we changing the auto height limits by dragging the signifiers? const { isAutoHeightWithLimitsChanging } = useAutoHeightUIState(); + const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); const dispatch = useDispatch(); @@ -327,7 +329,12 @@ export function DropTargetComponent(props: DropTargetComponentProps) { (e.target as HTMLDivElement).dataset.testid === selectionDiv || (e.target as HTMLDivElement).dataset.testid === mainCanvasId; - if (!isResizing && !isDragging && !isAutoHeightWithLimitsChanging) { + if ( + !isResizing && + !isDragging && + !isAutoHeightWithLimitsChanging && + !isWidgetSelectionBlocked + ) { // Check if Target is the MainCanvas if (isTargetMainCanvas) { goToWidgetAdd(); diff --git a/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx b/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx index ffe88063ef..ad5b71af17 100644 --- a/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx +++ b/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx @@ -23,6 +23,7 @@ import { combinedPreviewModeSelector, snipingModeSelector, } from "selectors/editorSelectors"; +import { getWidgetSelectionBlock } from "../../../selectors/ui"; const minSize = 100; /** @@ -101,7 +102,9 @@ export const ModalResizableLayer = ({ }; const isPreviewMode = useSelector(combinedPreviewModeSelector); const isSnipingMode = useSelector(snipingModeSelector); - const enableResizing = !isSnipingMode && !isPreviewMode; + const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); + const enableResizing = + !isSnipingMode && !isPreviewMode && !isWidgetSelectionBlocked; return ( ` - .${Classes.POPOVER_TARGET} { - height: 100%; - } -`; + const WidgetNameBoundary = 1; const BORDER_RADIUS = 4; const SettingsWrapper = styled.div<{ widgetWidth: number; inverted: boolean }>` @@ -60,10 +54,6 @@ const WidgetName = styled.span` white-space: nowrap; `; -const StyledErrorIcon = styled(Icon)` - margin-right: ${(props) => props.theme.spaces[1]}px; -`; - interface SettingsControlProps { toggleSettings: (e: any) => void; activity: Activities; @@ -111,17 +101,17 @@ const getStyles = ( export function SettingsControl(props: SettingsControlProps) { const isSnipingMode = useSelector(snipingModeSelector); - const errorIcon = ; + const errorIcon = ; return ( - + {isSnipingMode ? `Bind to widget ${props.name}` : `Edit widget`} + } - hoverOpenDelay={500} - position="top-right" + mouseEnterDelay={0} + placement="topRight" > - + ); } diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx index ccde7e6ba3..3bb3653d1f 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx @@ -30,6 +30,7 @@ import { getAbsolutePixels } from "utils/helpers"; import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; import { useCanvasDragToScroll } from "layoutSystems/common/canvasArenas/useCanvasDragToScroll"; import { StickyCanvasArena } from "layoutSystems/common/canvasArenas/StickyCanvasArena"; +import { getWidgetSelectionBlock } from "../../../../selectors/ui"; export interface SelectedArenaDimensions { top: number; @@ -71,6 +72,7 @@ export function CanvasSelectionArena({ ); const appMode = useSelector(getAppMode); const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); @@ -501,6 +503,7 @@ export function CanvasSelectionArena({ !( isDragging || isPreviewMode || + isWidgetSelectionBlocked || isAppSettingsPaneWithNavigationTabOpen || dropDisabled ); diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index 1b024f7939..87faf621f3 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -18,6 +18,7 @@ import { CANVAS_ART_BOARD } from "constants/componentClassNameConstants"; import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory"; import type { WidgetProps } from "widgets/BaseWidget"; import { getAppThemeSettings } from "@appsmith/selectors/applicationSelectors"; +import CodeModeTooltip from "pages/Editor/WidgetsEditor/CodeModeTooltip"; interface CanvasProps { widgetsStructure: CanvasWidgetStructure; @@ -83,20 +84,22 @@ const Canvas = (props: CanvasProps) => { const renderChildren = () => { return ( - - {props.widgetsStructure.widgetId && - renderAppsmithCanvas(props.widgetsStructure as WidgetProps)} - + + + {props.widgetsStructure.widgetId && + renderAppsmithCanvas(props.widgetsStructure as WidgetProps)} + + ); }; diff --git a/app/client/src/pages/Editor/IDE/MainPane/index.tsx b/app/client/src/pages/Editor/IDE/MainPane/index.tsx index bd2a5040b5..2f679302f5 100644 --- a/app/client/src/pages/Editor/IDE/MainPane/index.tsx +++ b/app/client/src/pages/Editor/IDE/MainPane/index.tsx @@ -4,11 +4,13 @@ import { Route, Switch, useRouteMatch } from "react-router"; import * as Sentry from "@sentry/react"; import useRoutes from "@appsmith/pages/Editor/IDE/MainPane/useRoutes"; import EditorTabs from "pages/Editor/IDE/EditorTabs/FullScreenTabs"; +import { useWidgetSelectionBlockListener } from "pages/Editor/IDE/hooks"; const SentryRoute = Sentry.withSentryRouting(Route); export const MainPane = (props: { id: string }) => { const { path } = useRouteMatch(); const routes = useRoutes(path); + useWidgetSelectionBlockListener(); return (

{ const [appState, setAppState] = useState(EditorState.EDITOR); @@ -215,3 +217,41 @@ export const useIsEditorPaneSegmentsEnabled = () => { return isEditorSegmentsReleaseEnabled || isEditorSegmentsRolloutEnabled; }; + +export function useWidgetSelectionBlockListener() { + const { pathname } = useLocation(); + const dispatch = useDispatch(); + const currentFocus = identifyEntityFromPath(pathname); + const isAltFocused = useSelector(getIsAltFocusWidget); + const widgetSelectionIsBlocked = useSelector(getWidgetSelectionBlock); + + useEffect(() => { + const inUIMode = [ + FocusEntity.CANVAS, + FocusEntity.PROPERTY_PANE, + FocusEntity.WIDGET_LIST, + ].includes(currentFocus.entity); + dispatch(setWidgetSelectionBlock(!inUIMode)); + }, [currentFocus]); + + useEffect(() => { + window.addEventListener("keydown", handleKeyDown); + window.addEventListener("keyup", handleKeyUp); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + window.removeEventListener("keyup", handleKeyUp); + }; + }, [isAltFocused, widgetSelectionIsBlocked]); + const handleKeyDown = (e: KeyboardEvent) => { + if (!isAltFocused && widgetSelectionIsBlocked && e.metaKey) { + dispatch(altFocusWidget(e.metaKey)); + } + }; + + const handleKeyUp = (e: KeyboardEvent) => { + if (!e.metaKey && widgetSelectionIsBlocked) { + dispatch(altFocusWidget(e.metaKey)); + } + }; +} diff --git a/app/client/src/pages/Editor/WidgetsEditor/CodeModeTooltip.tsx b/app/client/src/pages/Editor/WidgetsEditor/CodeModeTooltip.tsx new file mode 100644 index 0000000000..9c1e2e8a17 --- /dev/null +++ b/app/client/src/pages/Editor/WidgetsEditor/CodeModeTooltip.tsx @@ -0,0 +1,36 @@ +import { Tooltip } from "design-system"; +import React, { useEffect, useState } from "react"; +import { modText } from "utils/helpers"; +import { useSelector } from "react-redux"; +import { getWidgetSelectionBlock } from "selectors/ui"; +import { retrieveCodeWidgetNavigationUsed } from "utils/storage"; + +const CodeModeTooltip = (props: { children: React.ReactElement }) => { + const isWidgetSelectionBlock = useSelector(getWidgetSelectionBlock); + const [shouldShow, setShouldShow] = useState(false); + useEffect(() => { + retrieveCodeWidgetNavigationUsed() + .then((timesUsed) => { + if (timesUsed < 2) { + setShouldShow(true); + } + }) + .catch(() => { + setShouldShow(true); + }); + }, [isWidgetSelectionBlock]); + if (!isWidgetSelectionBlock) return props.children; + return ( + + {props.children} + + ); +}; + +export default CodeModeTooltip; diff --git a/app/client/src/reducers/uiReducers/dragResizeReducer.ts b/app/client/src/reducers/uiReducers/dragResizeReducer.ts index fb41c9872f..dd52089a0c 100644 --- a/app/client/src/reducers/uiReducers/dragResizeReducer.ts +++ b/app/client/src/reducers/uiReducers/dragResizeReducer.ts @@ -22,6 +22,8 @@ const initialState: WidgetDragResizeState = { isDistributingSpace: false, }, isDraggingDisabled: false, + blockSelection: false, + altFocus: false, }; export const widgetDraggingReducer = createImmerReducer(initialState, { @@ -100,11 +102,20 @@ export const widgetDraggingReducer = createImmerReducer(initialState, { }, [ReduxActionTypes.FOCUS_WIDGET]: ( state: WidgetDragResizeState, - action: ReduxAction<{ widgetId?: string }>, + action: ReduxAction<{ widgetId?: string; alt?: boolean }>, ) => { if (state.focusedWidget !== action.payload.widgetId) { state.focusedWidget = action.payload.widgetId; } + if (state.altFocus !== action.payload.alt) { + state.altFocus = !!action.payload.alt; + } + }, + [ReduxActionTypes.ALT_FOCUS_WIDGET]: ( + state: WidgetDragResizeState, + action: ReduxAction, + ) => { + state.altFocus = action.payload; }, [ReduxActionTypes.SET_SELECTED_WIDGET_ANCESTRY]: ( state: WidgetDragResizeState, @@ -118,6 +129,12 @@ export const widgetDraggingReducer = createImmerReducer(initialState, { ) => { state.entityExplorerAncestry = action.payload; }, + [ReduxActionTypes.SET_WIDGET_SELECTION_BLOCK]: ( + state: WidgetDragResizeState, + action: ReduxAction, + ) => { + state.blockSelection = action.payload; + }, //space distribution redux [AnvilReduxActionTypes.ANVIL_SPACE_DISTRIBUTION_START]: ( state: WidgetDragResizeState, @@ -166,6 +183,8 @@ export interface WidgetDragResizeState { selectedWidgets: string[]; isAutoCanvasResizing: boolean; isDraggingDisabled: boolean; + blockSelection: boolean; + altFocus: boolean; } export default widgetDraggingReducer; diff --git a/app/client/src/sagas/WidgetSelectionSagas.ts b/app/client/src/sagas/WidgetSelectionSagas.ts index ecaf44e9e2..1fe5dbba35 100644 --- a/app/client/src/sagas/WidgetSelectionSagas.ts +++ b/app/client/src/sagas/WidgetSelectionSagas.ts @@ -24,12 +24,12 @@ import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidg import { all, call, put, select, take, takeLatest } from "redux-saga/effects"; import type { SetSelectionResult } from "sagas/WidgetSelectUtils"; import { - SelectionRequestType, assertParentId, getWidgetAncestry, isInvalidSelectionRequest, pushPopWidgetSelection, selectAllWidgetsInCanvasSaga, + SelectionRequestType, selectMultipleWidgets, selectOneWidget, shiftSelectWidgets, @@ -41,7 +41,11 @@ import { getIsFetchingPage, snipingModeSelector, } from "selectors/editorSelectors"; -import { getLastSelectedWidget, getSelectedWidgets } from "selectors/ui"; +import { + getLastSelectedWidget, + getSelectedWidgets, + getWidgetSelectionBlock, +} from "selectors/ui"; import { areArraysEqual } from "utils/AppsmithUtils"; import { quickScrollToWidget } from "utils/helpers"; import history, { NavigationMethod } from "utils/history"; @@ -56,6 +60,11 @@ import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; import { getWidgetSelectorByWidgetId } from "selectors/layoutSystemSelectors"; import { getAppViewerPageIdFromPath } from "@appsmith/pages/Editor/Explorer/helpers"; +import AnalyticsUtil from "../utils/AnalyticsUtil"; +import { + retrieveCodeWidgetNavigationUsed, + storeCodeWidgetNavigationUsed, +} from "../utils/storage"; // The following is computed to be used in the entity explorer // Every time a widget is selected, we need to expand widget entities @@ -208,9 +217,16 @@ function* appendSelectedWidgetToUrlSaga( invokedBy?: NavigationMethod, ) { const isSnipingMode: boolean = yield select(snipingModeSelector); + const isWidgetSelectionBlocked: boolean = yield select( + getWidgetSelectionBlock, + ); + const timesUsedCodeModeWidgetSelection: number = yield call( + retrieveCodeWidgetNavigationUsed, + ); const appMode: APP_MODE = yield select(getAppMode); const viewMode = appMode === APP_MODE.PUBLISHED; if (isSnipingMode || viewMode) return; + const { pathname } = window.location; const currentPageId: string = yield select(getCurrentPageId); const currentURL = pathname; @@ -225,6 +241,15 @@ function* appendSelectedWidgetToUrlSaga( persistExistingParams: true, selectedWidgets: [MAIN_CONTAINER_WIDGET_ID], }); + if (invokedBy === NavigationMethod.CanvasClick && isWidgetSelectionBlocked) { + AnalyticsUtil.logEvent("CODE_MODE_WIDGET_SELECTION"); + if (timesUsedCodeModeWidgetSelection < 2) { + yield call( + storeCodeWidgetNavigationUsed, + timesUsedCodeModeWidgetSelection + 1, + ); + } + } if (currentURL !== newUrl) { history.push(newUrl, { invokedBy }); } diff --git a/app/client/src/selectors/ui.tsx b/app/client/src/selectors/ui.tsx index 435410addc..2dfd0bef01 100644 --- a/app/client/src/selectors/ui.tsx +++ b/app/client/src/selectors/ui.tsx @@ -68,3 +68,16 @@ export const getIsImportingCurl = (state: AppState) => export const getIsConsolidatedPageLoading = (state: AppState) => state.ui.consolidatedPageLoad.isLoading; + +export const getIsAltFocusWidget = (state: AppState) => + state.ui.widgetDragResize.altFocus; + +export const getWidgetSelectionBlock = (state: AppState) => + state.ui.widgetDragResize.blockSelection; + +export const getAltBlockWidgetSelection = createSelector( + [getWidgetSelectionBlock, getIsAltFocusWidget], + (isWidgetSelectionBlock, isAltFocusWidget) => { + return isWidgetSelectionBlock ? !isAltFocusWidget : false; + }, +); diff --git a/app/client/src/selectors/widgetDragSelectors.ts b/app/client/src/selectors/widgetDragSelectors.ts index c962998b55..54343cb1cd 100644 --- a/app/client/src/selectors/widgetDragSelectors.ts +++ b/app/client/src/selectors/widgetDragSelectors.ts @@ -5,6 +5,7 @@ import { combinedPreviewModeSelector, snipingModeSelector, } from "./editorSelectors"; +import { getWidgetSelectionBlock } from "./ui"; export const getIsDragging = (state: AppState) => state.ui.widgetDragResize.isDragging; @@ -25,6 +26,7 @@ export const getShouldAllowDrag = createSelector( combinedPreviewModeSelector, snipingModeSelector, getIsAppSettingsPaneWithNavigationTabOpen, + getWidgetSelectionBlock, ( isResizing, isDragging, @@ -32,6 +34,7 @@ export const getShouldAllowDrag = createSelector( isPreviewMode, isSnipingMode, isAppSettingsPaneWithNavigationTabOpen, + widgetSelectionIsBlocked, ) => { return ( !isResizing && @@ -39,7 +42,8 @@ export const getShouldAllowDrag = createSelector( !isDraggingDisabled && !isSnipingMode && !isPreviewMode && - !isAppSettingsPaneWithNavigationTabOpen + !isAppSettingsPaneWithNavigationTabOpen && + !widgetSelectionIsBlocked ); }, ); diff --git a/app/client/src/selectors/widgetSelectors.ts b/app/client/src/selectors/widgetSelectors.ts index 20e64217bb..04144e6586 100644 --- a/app/client/src/selectors/widgetSelectors.ts +++ b/app/client/src/selectors/widgetSelectors.ts @@ -9,6 +9,7 @@ import { getNextEntityName } from "utils/AppsmithUtils"; import WidgetFactory from "WidgetProvider/factory"; import { + getAltBlockWidgetSelection, getFocusedWidget, getLastSelectedWidget, getSelectedWidgets, @@ -179,6 +180,7 @@ export const shouldWidgetIgnoreClicksSelector = (widgetId: string) => { getAppMode, combinedPreviewModeSelector, getIsAutoHeightWithLimitsChanging, + getAltBlockWidgetSelection, ( focusedWidgetId, isTableFilterPaneVisible, @@ -188,6 +190,7 @@ export const shouldWidgetIgnoreClicksSelector = (widgetId: string) => { appMode, isPreviewMode, isAutoHeightWithLimitsChanging, + isWidgetSelectionBlock, ) => { const isFocused = focusedWidgetId === widgetId; @@ -199,7 +202,8 @@ export const shouldWidgetIgnoreClicksSelector = (widgetId: string) => { appMode !== APP_MODE.EDIT || !isFocused || isTableFilterPaneVisible || - isAutoHeightWithLimitsChanging + isAutoHeightWithLimitsChanging || + isWidgetSelectionBlock ); }, ); diff --git a/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts b/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts index 6c1d2e734c..3d36241f26 100644 --- a/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts +++ b/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts @@ -7,6 +7,7 @@ import { useSelector } from "react-redux"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; import { LayoutSystemTypes } from "layoutSystems/types"; +import { getWidgetSelectionBlock } from "../../selectors/ui"; export const useAllowEditorDragToSelect = () => { // This state tells us whether a `ResizableComponent` is resizing @@ -46,6 +47,8 @@ export const useAllowEditorDragToSelect = () => { getIsAppSettingsPaneWithNavigationTabOpen, ); + const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); + return ( isFixedLayout && !isAutoCanvasResizing && @@ -53,6 +56,7 @@ export const useAllowEditorDragToSelect = () => { !isDraggingDisabled && !isSnipingMode && !isPreviewMode && - !isAppSettingsPaneWithNavigationTabOpen + !isAppSettingsPaneWithNavigationTabOpen && + !isWidgetSelectionBlocked ); }; diff --git a/app/client/src/utils/hooks/useWidgetSelection.ts b/app/client/src/utils/hooks/useWidgetSelection.ts index 2d275fd021..23b6a145af 100644 --- a/app/client/src/utils/hooks/useWidgetSelection.ts +++ b/app/client/src/utils/hooks/useWidgetSelection.ts @@ -1,4 +1,4 @@ -import { focusWidget } from "actions/widgetActions"; +import { altFocusWidget, focusWidget } from "actions/widgetActions"; import { selectWidgetInitAction } from "actions/widgetSelectionActions"; import { useCallback } from "react"; @@ -23,7 +23,8 @@ export const useWidgetSelection = () => { [dispatch], ), focusWidget: useCallback( - (widgetId?: string) => dispatch(focusWidget(widgetId)), + (widgetId?: string, altFocus?: boolean) => + dispatch(focusWidget(widgetId, altFocus)), [dispatch], ), deselectAll: useCallback( @@ -38,5 +39,8 @@ export const useWidgetSelection = () => { [dispatch], ), goToWidgetAdd: useCallback(() => history.push(builderURL({})), []), + altFocus: useCallback((alt: boolean) => { + dispatch(altFocusWidget(alt)); + }, []), }; }; diff --git a/app/client/src/utils/storage.ts b/app/client/src/utils/storage.ts index a0aaac610e..42914ece99 100644 --- a/app/client/src/utils/storage.ts +++ b/app/client/src/utils/storage.ts @@ -38,6 +38,7 @@ export const STORAGE_KEYS: { AI_KNOWLEDGE_BASE: "AI_KNOWLEDGE_BASE", PARTNER_PROGRAM_CALLOUT: "PARTNER_PROGRAM_CALLOUT", IDE_VIEW_MODE: "IDE_VIEW_MODE", + CODE_WIDGET_NAVIGATION_USED: "CODE_WIDGET_NAVIGATION_USED", }; const store = localforage.createInstance({ @@ -882,3 +883,26 @@ export const retrieveIDEViewMode = async (): Promise< log.error(error); } }; + +export const storeCodeWidgetNavigationUsed = async (count: number) => { + try { + await store.setItem(STORAGE_KEYS.CODE_WIDGET_NAVIGATION_USED, count); + return true; + } catch (error) { + log.error("An error occurred while setting CODE_WIDGET_NAVIGATION_USED"); + log.error(error); + } +}; + +export const retrieveCodeWidgetNavigationUsed = async (): Promise => { + try { + const mode = (await store.getItem( + STORAGE_KEYS.CODE_WIDGET_NAVIGATION_USED, + )) as number; + return mode || 0; + } catch (error) { + log.error("An error occurred while fetching CODE_WIDGET_NAVIGATION_USED"); + log.error(error); + return 0; + } +}; diff --git a/app/client/src/widgets/TableWidgetV2/component/header/actions/filter/FilterPane.tsx b/app/client/src/widgets/TableWidgetV2/component/header/actions/filter/FilterPane.tsx index 4da3d76e0f..c7a4e5f028 100644 --- a/app/client/src/widgets/TableWidgetV2/component/header/actions/filter/FilterPane.tsx +++ b/app/client/src/widgets/TableWidgetV2/component/header/actions/filter/FilterPane.tsx @@ -19,8 +19,6 @@ import { getTableFilterState } from "selectors/tableFilterSelectors"; import { getWidgetMetaProps } from "sagas/selectors"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; import type { WidgetProps } from "widgets/BaseWidget"; -import { selectWidgetInitAction } from "actions/widgetSelectionActions"; -import { SelectionRequestType } from "sagas/WidgetSelectUtils"; import { importSvg } from "design-system-old"; import { CANVAS_ART_BOARD } from "constants/componentClassNameConstants"; @@ -155,14 +153,12 @@ const mapDispatchToProps = (dispatch: any) => { position, }, }); - dispatch(selectWidgetInitAction(SelectionRequestType.One, [widgetId])); }, hideFilterPane: (widgetId: string) => { dispatch({ type: ReduxActionTypes.HIDE_TABLE_FILTER_PANE, payload: { widgetId }, }); - dispatch(selectWidgetInitAction(SelectionRequestType.One, [widgetId])); }, }; };