0.0.6 • Published 1 year ago

@artsofte/esw v0.0.6

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

ESW Docs

Общее

Платформа nocode имеет возможность встраивания виджетов. Виджет - это программный код выполняющийся на стороне нашей платформы. Виджет может отображать данные, делать запросы на сторонние ресурсы, взаимодействовать с сущностями платформы nocode

Реализация виджета

Простейший виджет

Сначала вам нужно реализовать сам виджет. Виджет - это js файл. Так выглядит самый простой виджет, который выводит на экран текст "Hello, world"

window.eswInit = () => {
  return new SimpleWidget();
};

class SimpleWidget {
  constructor() {
    const renderRoot: HTMLElement = getEswNamespace().renderRoot;
    renderRoot.innerText = "Hello, NoCode!";
  }
}

Наша платформа при работе с вашим файлом рассчитывает на наличие глобальной функции eswInit, которая возвращает инстанс виджета. Далее у этого инстанса будут вызываться хуки жизненного цикла.

 Использование TypeScript

Мы предоставляем npm пакет с декларациями типов сущностей платформы. Загрузить его можно с помощью команды

npm i @artsofte/esw

Исходный код и примеры

С кодом библиотеки @artsofte/esw можно ознакомиться на Github. Также можете ознакомиться с примерами виджетов Examples

Хуки жизненного цикла виджета

EswIsValid

Пример использования:

import { EswIsValid } from "@artsofte/esw";

window.eswInit = () => {
  return new SimpleWidget();
};

class SimpleWidget implements EswIsValid {
  public eswIsValid(): boolean {
    return true;
  }
}

При попытке клиента перехода на следующий шаг - виджеты на форме должны быть валидными. Если виджет не валиден, то система не позволяет пройти на следующий шаг. Если ваш виджет реализует интерфейс EswIsValid, то при попытке перехода на следующий шаг будет вызван метод eswIsValid.

EswAfterUnmount

Пример использования:

import { EswAfterUnmount } from "@artsofte/esw";

window.eswInit = () => {
  return new SimpleWidget();
};

class SimpleWidget implements EswAfterUnmount {
  private intervalId: number;

  constructor() {
    this.intervalId = setInterval(() => console.log("Hello, world"), 1000);
  }

  public eswAfterUnmount(): void {
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
  }
}

Хук, обозначающий, что разметка вашего виджета уже удалена из DOM. Чаще всего используется для очистки таймеров, подписок.

EswOnSettingsChange

Пример использования:

import { Catalog, EswOnSettingsChange, GetSettingsReturn } from "@artsofte/esw";

interface IWidgetSettings {
  catalog: Catalog<{ name: string; value: string }>;
}

window.eswInit = (config: IWidgetSettings) => {
  return new CatalogReader(config);
};

window.eswInitSettings = (): GetSettingsReturn => {
  return {
    version: "v1",
    settings: [
      {
        type: "catalog",
        label: "Отображаемый каталог",
        saveTo: "catalog",
      },
    ],
  };
};

class CatalogReader implements EswOnSettingsChange {
  private readonly renderRoot: HTMLElement = getEswNamespace().renderRoot;

  constructor(private config: IWidgetSettings) {}

  public eswOnSettingsChange(config: IWidgetSettings): void {
    this.config = config;
    this.renderCatalogData();
  }

  private renderCatalogData(): void {
    this.config.catalog.content().then((data) => {
      this.renderRoot.innerText = JSON.stringify(data);
    });
  }
}

Данный хук вызывается при каждом изменении настроек в правом сайд-баре со стороны провайдера. Стоит обратить внимание на то, что данный хук не будет ни разу вызван при рендеринге виджета на клиентской форме.

Вывод настроек для провайдера

Платформа имеет встроенные механизмы справочников, модели документа и другие. Виджету требуется взаимодействие с ними. Всегда доступ к тем или иным сущностям выдает провайдер в правом сайд-баре. Например, виджет хочет записывать данные в модель документа. Тогда провайдер в правом сайде-баре выбирает область в модели документа, куда виджет имеет право писать данные. Другой пример, виджет хочет получить доступ до каталога: провайдер выбирает к какому каталогу именно виджет имеет доступ. Чтобы указать, какие настройки требуются - реализуйте глобальную функцию eswInitSettings. У каждой настройки есть параметр saveTo, этот параметр обозначает путь, куда в конфиге буду сохранены данные.

window.eswInitSettings = (): EswSettingsDeclaration => {
    return {
        version: "v1",
        settings: [
            {
                ...,
                saveTo: "param"
            }
        ]
    }
}

interface WidgetSettings {
    param: ... 
}

window.eswInit = (config: WidgetSettings) => {
    ...
}

Важно понимать, что при рендеринге на стороне провайдера config в метод eswInit будет пустым, так как провайдер еще не выбрал настройки. Объект будет наполняться по мере наполнения настроек провайдером.

Запись в модель документа

Виджет может записывать данные в модель документа. Для этого виджет должен вернуть требуемые настройки в методе initSettings

import {
  DocumentElement,
  EswAfterUnmount,
  GetSettingsReturn,
} from "@artsofte/esw";

window.eswInit = (config: IWidgetSettings) => {
  return new SimpleWidget(config);
};

interface IWidgetSettings {
  documentToken: DocumentElement<{ someData: string }>;
}

window.eswInitSettings = (): EswSettingsDeclaration => {
  return {
    version: "v1",
    settings: [
      {
        type: "documentElementWrite",
        label: "Запись в модель документа",
        saveTo: "documentToken",
        isRequired: true,
      },
    ],
  };
};

class SimpleWidget implements EswAfterUnmount {
  private readonly renderRoot: HTMLElement = getEswNamespace().renderRoot;

  private readonly intrevalId: number = 0;

  constructor(config: IWidgetSettings) {
    const isProvider = getEswNamespace().env.isProvider;

    if (isProvider) {
      this.renderProviderView();

      return;
    }

    let count = 0;

    this.intrevalId = setInterval(() => {
      count += 1;
      config.documentToken.patch("count", { value: count });
      this.renderRoot.innerHTML = `Count: ${count}`;
    }, 1000);
  }

  public eswAfterUnmount() {
    clearInterval(this.intrevalId);
  }

  private renderProviderView() {
    this.renderRoot.innerHTML = "Виджет патчит документ каждую секунду";
  }
}

Справочники

Виджет может читать данные из справочника, который к нему привяжет провайдер

import { Catalog, GetSettingsReturn } from "@artsfote/esw";

interface IWidgetSettings {
  catalog: Catalog<{ name: string; value: string }>;
}

window.eswInit = (config: IWidgetSettings) => {
  return new CatalogReader(config);
};

window.eswInitSettings = (): EswSettingsDeclaration => {
  return {
    version: "v1",
    settings: [
      {
        type: "catalog",
        label: "Отображаемый каталог",
        saveTo: "catalog",
      },
    ],
  };
};

class CatalogReader {
  private readonly renderRoot: HTMLElement = getEswNamespace().renderRoot;

  constructor(config: IWidgetSettings) {
    const isProvider = getEswNamespace().env.isProvider;

    if (isProvider) {
      this.renderProviderView();
    } else {
      config.catalog.content()
        .then((data) => this.render(data))
        .catch(() => this.renderError());
    }
  }

  private renderProviderView(): void {
    this.renderRoot.innerHTML = "Отображение каталогов";
  }

  private render(data: any): void {
    this.renderRoot.innerHTML = JSON.stringify(data);
  }

  private renderError(): void {
    this.renderRoot.innerHTML = "Ошибка чтения справочника";
  }
}

Другие настройки

  • select отображение селекта. В saveTo будет записан SelectItem

Использование бибилотек и фреймворков

Разработчик виджета может использовать любые доступные технологии. В директории examples есть примеры использования некоторых технологий. Платформа разрешает загружать как единый JS бандл, так и дает возможность загрузки множества скриптов по url. Нужно учесть, что рендеринг вашего скрипта происходит в shadow root, поэтому, нужно указать вашей библиотеке/фреймворку в какой именно HTML узел помещать разметку. Сам этот HTML узел можно получить вызвав следующий код: getEswNamespace().renderRoot

Ограничения

Рендеринг вашего html происходит вне встроенного iframe, а в рамках основного DOM в shadow-root. Это значит, что существует две разные среды JS, а значит разные инстансы глобальных объектов. Например, вы прослушиваете событие клика по кнопке. К прослушиванию добавляете callback, который принимает event с типом MouseEvent. Событие происходит в рамках основного DOM и передается в функцию, которая работает в рамках iframe. Поэтому проверка event instanceof MouseEvent не сработает. Так как event был создан в рамках основного окна и в прототипе лежит ссылка на MouseEvent основного окна. А вы совершаете проверку с MouseEvent вашего окна, в котором свои глобальные объект, никак не связанные с глобальными объектами основного окна.

Также часто можно наблюдать, когда создается прослушиватель на весь документ (document.addEventListener('click', () => {})). Это не будет работать в рамках виджета, так как document будет являться документом айфрейма. А так как iframe находится в head секции основного DOM, то клик по нему никогда не происходит. Нужно создавать прослушиватели только на свой корневой div элемент. Получить его можно при помощи getEswNamespace().renderRoot

0.0.5

1 year ago

0.0.6

1 year ago

0.0.4

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago