dashpresshq/dashpress

View on GitHub
src/frontend/docs/scripts/form-scripts.tsx

Summary

Maintainability
C
7 hrs
Test Coverage
A
100%
import { RenderCode } from "@/components/app/render-code";

import { DocumentationRoot } from "../_base";

export function FormScriptDocumentation() {
  return (
    <DocumentationRoot>
      <p>
        Forms scripts enable you to implement the complex form logic your
        business requirements require that the UI cannot achieve.
      </p>
      <p>
        In the <code>Form Scripts</code>, you will have access to the following
        variables:
        <ul>
          <li>
            <b>
              <code>$.formValues</code>
            </b>
            : This gives you current form values.
          </li>
          <li>
            <b>
              <code>$.action</code>
            </b>
            : The values are either{" "}
            <code>&quot;update&quot; | &quot;create&quot;</code> which allows
            you to condition the script for the creation or update form.
          </li>
          <li>
            <b>
              <code>$.auth</code>
            </b>
            : The current user details
          </li>
          <li>
            <b>
              <code>$.routeParams</code>
            </b>
            : The current entity details
          </li>
        </ul>
      </p>
      <p>
        Form scripts are run on the client and they are not async so you
        can&apos;t make Promises or make network calls.{" "}
      </p>
      <p>
        We have three tabs where which do different things so let&apos;s start
        with the first
      </p>
      <h3>1. Field State</h3>
      <p>
        This allows you to hide or disable your form fields. Let&apos;s dive
        straight into examples
      </p>
      <RenderCode
        input={`// This script will disable the "accountBalance" field.
return {
  accountBalance: {
    disabled: true
  }
}

// This will hide the "accountBalance" field
return {
  accountBalance: {
    hidden: true
  }
}

/*
This will disable the "canRegister" field
when the value of "age" is less than 18
*/
return {
  canRegister: {
    disabled: $.formValues.age < 18
  },
}

/* 
This will hide the "whatCanWeDoBetter" field 
when the value of "rating" is equal than 5
*/
return {
  whatCanWeDoBetter: {
    hidden: $.formValues.rating == 5
  }
}

/* 
This will hide the "accountBalance" field 
when the current user is updating his account  
*/
return {
  accountBalance: {
    hidden: $.auth.username === $.routeParams.entityId
  }
}

/* 
There is no limit to the composition 
*/
return {
  field1: {
    hidden: someLogic == true
  },
  field2: {
    disabled: someLogic == false,
    hidden: someLogic == true,
  },
  field3: {
    hidden: someLogic != true
  }
}
`}
      />
      <p>
        We use the field name, not the field label. For example, if you want to
        target the <code>accountBalance</code>, using{" "}
        <code>Account Balance </code>
        will not work or any label that is shown in the form. What is used is
        the database field name which is <code>accountBalance</code> any other
        label will not work.{" "}
      </p>
      <h3>2. Before Submit</h3>
      <p>This tab enables you to do two different things.</p>
      <h5>1. Run custom validation</h5>
      <p>
        Data validation can easily become complex and with this tab, you should
        be able to tame the complexity of your validation requirements.
      </p>
      <p>
        This is how it works, When a string is returned from this tab, then the
        value is seen as an error which will be shown to the user and the form
        will not be submitted.
      </p>

      <RenderCode
        input={`/*
This script will not allow users submit the form
and will be seeing the message in an alert,
*/
return "You shall not pass"

/* 
For more practical use, you will want to wrap the text 
in a logic block and can it be as complex as needed
*/
if(
    $.formValues.age > 1000 && 
    (
      $.formValues.planet != "Earth" ||
      $.formValues.technology == "Advance" 
    )
  ) {
  return "Only Aliens can submit this form"
}

// This is plain Javascript so you can write functions too.
const customFunctionToReturnFalse = () => false

if(customFunctionToReturnFalse()){
    return "Custom function returned false"
}

// Once the script validation gets to the bottom
// then it will be submitted`}
      />

      <p>
        The validations parsed from your database and the ones you added from
        the <code>Fields</code> tab will run first before the ones on this
        script.
      </p>

      <h5>2. Modify the form values</h5>
      <p>
        The second use for this tab to is modify the data you are submitting.
      </p>
      <p>
        This is how it works, If you return an <code>object</code>, then that
        object will be what will be submitted. This allows you to append and
        remove fields to the original submitted data.
      </p>
      <RenderCode
        input={`/*
Will add "createdById" to the form values that is to be submitted
*/
return {
  ...$.formValues,
  createdById: $.auth.userId
}

/*
Will add "createdAt" to the form values that is to be submitted
*/
return {
  ...$.formValues,
  createdAt: new Date(),
}

/*
You can compute fields to save
*/
return {
  ...$.formValues,
  slug: $.formValues.title?.replaceAll(" ", "-").toLowerCase()
}`}
      />
      <p>
        Needless to say, you can combine both <code>Before Submit</code> usages
        to both validate data before submitting and transform the data when
        submitting in the same script.
      </p>
      <RenderCode
        input={`/**
 * Will validate the form and will throw the error when it returns a string
 * And will add "createdById" when the form is submitted
 */
if($.formValues.age > 23 && ($.formValues.country != "Belgium" || $.formValues.height == 124 )){
  return "This is a weird requirement and DashPress can handle it"
}

return {
  ...$.formValues,
  createdById: $.auth.userId
}`}
      />

      <h3>3. Initial Values</h3>
      <p>
        This tab simply allows you to set the initial values for the create form
      </p>
      <RenderCode
        input={`/**
 * Will the follow values as intial values on the create form
 */

return {
  price: 1000,
  status: "new",
  country: "US",
  isApproved: true
}`}
      />
      <p>You will not have access to any variables here, so no `$.anything`</p>
    </DocumentationRoot>
  );
}