{"id":13545911,"url":"https://github.com/surajp/lightning-js-button","last_synced_at":"2025-04-02T17:32:19.854Z","repository":{"id":39829733,"uuid":"267781297","full_name":"surajp/lightning-js-button","owner":"surajp","description":"JavaScript buttons that work in Lightning!","archived":false,"fork":false,"pushed_at":"2023-02-09T03:03:36.000Z","size":1628,"stargazers_count":26,"open_issues_count":13,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-03T14:34:44.925Z","etag":null,"topics":["apex","aura","button","javascript","js-buttons","lightning","lightning-web-component","lightning-web-components","lwc","salesforce","salesforce-apis","soql"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/surajp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-05-29T06:21:03.000Z","updated_at":"2024-08-15T14:12:32.000Z","dependencies_parsed_at":"2024-03-16T16:37:16.316Z","dependency_job_id":"08f25a5b-429d-47f0-a97e-b27b4669f0ce","html_url":"https://github.com/surajp/lightning-js-button","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surajp%2Flightning-js-button","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surajp%2Flightning-js-button/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surajp%2Flightning-js-button/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surajp%2Flightning-js-button/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/surajp","download_url":"https://codeload.github.com/surajp/lightning-js-button/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246860198,"owners_count":20845629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apex","aura","button","javascript","js-buttons","lightning","lightning-web-component","lightning-web-components","lwc","salesforce","salesforce-apis","soql"],"created_at":"2024-08-01T12:00:26.673Z","updated_at":"2025-10-14T12:09:59.483Z","avatar_url":"https://github.com/surajp.png","language":"JavaScript","funding_links":[],"categories":["On Platform Community Repos"],"sub_categories":[],"readme":"# Pure JS Buttons in Lightning\n\nJS buttons are back in Lightning! (For now, at least) And they are even more\npowerful than JS buttons in classic. Run SOQL and DML statements seamlessly.\nMake callouts to APIs, including Salesforce APIs directly from JavaScript!\nThis would allow you to build buttons that do amazing things, just using\nJavaScript. Check out the [scripts](./scripts/jsButton) folder for examples.\nFeel free to raise a PR to contribute your own scripts.\n\n### The Setup\n\nThe button can be made available to users via a quick action powered by the\n`jsButtonQuickAction` component. The actual JavaScript should be entered into a\n`JS_Button__mdt` custom metadata record, into the `Script__c` field with the\nsame name as the name of the SObject. The repo contains a couple of samples\nfor `Account` and `Contact`. The corollary is that, out of the box, only one\nbutton per SObjectType may be supported, for quick actions. You can add any\nnumber of buttons on the flexipage, with the underlying JS added using the\nflexipage builder.\n\n### APIs\n\nThe library supports the following apis\n\n- soql\n- dml (dml.insert, dml.update, dml.upsert and dml.del ) // `delete` is a resrved keyword :(\n- callout ( used for calling external services through Apex. Named credentials are supported! )\n- sfapi ( used for calling Salesforce APIs from the same org. Requires CORS and\n  CSP Trusted Sites setup. Details below)\n- toast ( show a platform toast message )\n\n### The Syntax\n\nThis is the fun part. I haven't, obviously, explored all possible scenarios and\nthe information may still be incomplete. Please raise an issue if you come\nacross something I haven't covered.\n\n- Simple examples (no soql/dml)\n\n```js\nalert(\"hello,world\");\n```\n\n```js\ntoast(\n  Array(5)\n    .fill(0)\n    .map((e, i) =\u003e \"Hello, \" + i)\n); /* `toast` service to show message toasts */\n```\n\n- Fetch 100 of the latest Accounts and for upto 10 of the ones without a Contact, add a Contact\n\n```js\nlet accts = await soql(\n  `Select Name,(Select Id from Contacts) from Account order by createddate desc\n  limit 100`\n); /* Querying child records is supported */\nlet contacts = accts\n  .filter((a) =\u003e !a.Contacts || a.Contacts.length === 0)\n  .slice(0, 10)\n  .map((a) =\u003e ({ LastName: a.Name + \"-Contact\", AccountId: a.Id }));\nlet contactIds = await dml.insert(\n  contacts,\n  \"Contact\"\n); /*Note how the SObjectType has been specified. This is required for insert and upsert*/\n$A.get(\"e.force:refreshView\").fire(); /* $A is supported!*/\n```\n\n- Act in the context of the current record\n\n```js\nlet acct = await soql(\n  `Select NumberOfEmployees from Account where Id='${recordId}'`\n); /* Note the use of template literal syntax to resolve \nvariable values in the query */\nacct[0].NumberOfEmployees = (acct[0].NumberOfEmployees || 0) + 10;\nlet acctId = await dml.update(acct);\nacct = await soql(`Select NumberOfEmployees from Account where Id='${acctId}'`);\ntoast(acct[0].NumberOfEmployees, \"success\");\n$A.get(\"e.force:refreshView\").fire();\n```\n\n- Add a 'File' to the current record\n\n```js\nlet fileContent = btoa(\"Hello World\");\n/* convert your file content to base64 data before uploading */\nlet cv = {\n  VersionData: fileContent,\n  Title: \"My Awesome File\",\n  PathOnClient: \"MyFile.txt\",\n  FirstPublishLocationId: recordId\n};\nlet cvId = await dml.insert(cv, \"ContentVersion\");\ntoast(\"New file Added\", \"success\");\n$A.get(\"e.force:refreshView\").fire();\n```\n\n### About the Syntax\n\n- Note how the syntax is linear for SOQL and DML. Coupled with JavaScript's\n  support for manipulating arrays, this makes it easier to manipulate data,\n  even compared to Apex in several instances.\n- `dml.insert` and `dml.upsert` expect the SObjectType as the second argument.\n  Thus `dml.insert(acct,\"Account\")`\n- Statements with contextual arguments such as `recordId`\n  are best expressed using [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).\n- All statements must be strictly terminated by a semicolon.\n\n### Known Limitations\n\n- Single-line comments are not supported.\n- Haven't tested DML with date, datetime, boolean, geolocation and other\n  compound fields. I will update this section as I do so.\n- To insert `ContentVersion` make sure to set `VersionData` to base64 data.\n  Refer to the example [here](./scripts/jsButton/createContactFiles.js) for details.\n- The maximum size of files I was able to upload was around 2 MB.\n  Anything larger will fail silently due to heap size limits in Apex\n\n### Using Salesforce (and other) APIs in your script\n\nTo use Salesforce APIs from your org, using the `sfapi` method, take the following steps:\n\n- Add your lightning domain (ends with `lightning.force.com`) to the `CORS` list under `Setup`.\n- Add your classic domain to `CSP Trusted Sites` list under `Setup`.\n\nThis allows you to write scripts for admins to perform tasks like [deleting inactive versions of flows](./scripts/jsButton/deleteInactiveFlowVersions.js) or [use composite api](./scripts/jsButton/compositeApiExample.js)\nfor creating parent and child records.\nTo access protected APIs such as those from other Salesforce orgs, use a named credential and the `callout` api. For Public APIs, you can use `fetch` directly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurajp%2Flightning-js-button","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsurajp%2Flightning-js-button","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurajp%2Flightning-js-button/lists"}