Ignition 8.3: Guidance/example on end-to-end WebUI / Gateway interaction

OK thanks for the input, I was able to get everything going.

@pturmel’s pointer to 8.3 File Upload route permissions issue - #8 by pturmel was really key for posting – i.e., whenever you use PermissionType.WRITE. I was able to access the ReduxRootState exactly as he did. Otherwise you will get a non-descript 403 Forbidden error.

For those following along and looking for more examples of what works, here’s what my mountRouteHandlers() looked like in my GatewayHook class:

    public void mountRouteHandlers(RouteGroup routes) {
        routes.newRoute("/settings")
                .type(RouteGroup.TYPE_JSON)
                .handler(this::getSettingsJson)
                .method(HttpMethod.GET)
                .requirePermission(PermissionType.READ)
                .mount();

        routes.newRoute("/settings")
                .type(RouteGroup.TYPE_JSON)
                .handler(this::putSettingsJson)
                .method(HttpMethod.PUT)
                .requirePermission(PermissionType.WRITE)
                .mount();
    }

and here’s what my Settings.service.ts looks like on the frontend:

export const getSettings = async (): Promise<SeeqSettings> => {
  const response = await fetch("/data/seeq/settings", {
    method: "GET",
    headers: {
      Accept: "application/json",
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch settings: ${response.statusText}`);
  }

  const payload: SeeqSettingsPayload = await response.json();

  // Flatten the structure for UI convenience
  return {
    enabled: payload.enabled,
    ...payload.config,
  };
};

export const updateSettings = async (
  settings: Partial<SeeqSettings>,
  csrfToken: string
): Promise<UpdateSettingsResponse> => {
  // Extract enabled and wrap the rest in config
  const { enabled, ...config } = settings;

  const payload: Partial<SeeqSettingsPayload> = {
    enabled,
    config: config as IgnitionModuleConfigurationV2,
  };

  const response = await fetch("/data/seeq/settings", {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      "X-CSRF-Token": csrfToken,
    },
    body: JSON.stringify(payload),
  });

  const data: UpdateSettingsResponse = await response.json();

  // Check if the operation was successful
  if (!data.success) {
    throw new Error(data.message || "Failed to update settings");
  }

  return data;
};

where csrfToken was retrieved via this code:

  const csrfToken = useSelector(
    (state: ReduxRootState) => state.userSession.csrfToken || ""
  );
2 Likes