CORS error when trying to use smart components in workspace

Feature(s) impacted

I’m looking to use the Workspace Smart component. After creating the template.hbs file and deploying it on our backend, I tried entering the URL in the template URL field as “/public/smart-components/amount/template.hbs” and also tried “public/smart-components/amount/template.hbs”. However, I keep receiving an error, and the logs show the following:

[backend_url]public/smart-components/amount/template.hbs’ from origin ‘https://app.forestadmin.com’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

Expected behavior

Expecting for my smart component to load my template

Failure Logs

Context

  • Project name: Ourboro
  • Team name: Customer Experience
  • Environment name: ourboro-development
  • Agent technology: nodejs
  • Agent (forest package) name & version: “@forestadmin/agent”: “^1.59.0”,
  • Database type: postgres
  • Recent changes made on your end if any: …

Hello @Zero

You will need to mount your agent on an express application, configure the CORS for your express app, and create routes for your files.

import express from 'express';
import cors from 'cors';

// ... 

app.use(cors({
  origin: ['https://app.forestadmin.com'],
  methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
  credentials: true,
}))

agent.mountOnExpress(app).start();

// Then create routes for your files
app.get('/smart-components/amount/template', (req, res, next) => {
  res.set('Content-Type', 'text/html');
  return res.send(fs.readFileSync(path.join(__dirname, 'public/smart-components/amount/template.hbs')));
})

Then you should be able to use /smart-components/amount/template in the smart component configuration.

Nicolas

Thank you — I got that to work in the same category for smart components. The issue I’m now facing is with adding a smart action, as described in the documentation I found.

Blockquote: For triggering a smart action it’s the exact same code as inside a smart view. Please follow this link.

For example, in my workspace, I have a collection called processRecordCollection. I’m able to pass in the selected record ID from that collection — I’ve confirmed this by logging it out.

However, the problem is with the @collection part. In a typical smart action, the collection is already known because the smart view is created within that collection. But in a workspace, you can have multiple collections. So, in this case, how do we pass the collection into the smart action?

<Button::BetaButton
  @type="primary"
  @text="Reschedule appointment"
  @action={{fn this.triggerSmartAction @collection 'Reschedule' record}}
/>

The collection I’m trying to pass is homeownersProcessrecord. Any insight on this would be greatly appreciated — I’ve been stuck on this for a while.

@nbouliol just wanted to check if you have any insights into this issue

Hello @Zero

Sorry for the delay.

The documentation for the smart component is not up to date, yan can’t call smart actions the same way you would in a smart view.

You should be able to call the smart action inside the custom component using the following:

// template.hbs
{{#if this.isContextSet}}
  <Button::BetaButton
    @type="primary"
    @text="Trigger the action"
    @action={{this.triggerAction}}
    @withoutCallback={{true}}
  />
{{else}}
  <p>context not set - select a record</p>
{{/if}}
// component.js
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { service } from "@ember/service";

const SMART_ACTION_NAME = "Change the flavor";

export default class extends Component {
  @service store;
  @service("feature/action") actionService;

  @action
  triggerAction() {
    const smartAction = this.store
      .peekAll("custom-action")
      .find((action) => action.name === SMART_ACTION_NAME);

    // you can add a third param to pass values to your smart action
    return this.actionService.triggerCustomAction(smartAction, [this.record]);
  }

  get record() {
    return this.args.component.templatingHelper.getVariableValue(
      "collection1.selectedRecord"
    );
  }

  get isContextSet() {
    return this.args.component.templatingHelper.isContextSet(
      "{{collection1.selectedRecord}}"
    );
  }
}

However this code is using our private API, so it might break at some point.

Hi thank you this worked, one last thing to pass in a value to the smart action it doesn’t seem to be working as when I try this code I get this error “A value is required for field Note”

    return this.actionService.triggerCustomAction(smartAction, [this.record], [{Note: "testing"}]);

In our smart action this is the form data we have

form: [
{
id: ‘Note’,
label: ‘Note’,
isRequired: true,
type: ‘String’,
widget: ‘RichText’,
placeholder: ‘Enter your note’
}
],

Hello

Can you try to pass the additional values as an object ?

return this.actionService.triggerCustomAction(smartAction, [this.record], {Note: "testing"});

hi tried that as well and still the same error

Hello,

You can disable isRequired from your action field to remove the error.