@retailcrm/embed-ui 0.9.30-alpha.1 → 0.9.30-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/bin/embed-ui.mjs +1 -50
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.30-alpha.2
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* **v1-sandbox:** corrected sandbox context reload lifecycle and refactor class style, added skip e2e block without env value ([88866f0](https://github.com/retailcrm/embed-ui/commit/88866f0d9ea2a6cd61fe6ef9c5d5448b67965d39))
|
|
8
|
+
|
|
3
9
|
## 0.9.30-alpha.1
|
|
4
10
|
|
|
5
11
|
### Features
|
package/bin/embed-ui.mjs
CHANGED
|
@@ -2158,56 +2158,7 @@ const readmeEnGBTemplate = "# RetailCRM extension frontend\n\nThis project was g
|
|
|
2158
2158
|
const readmeEsESTemplate = "# Frontend de extension RetailCRM\n\nEste proyecto fue generado por `embed-ui init`.\n\n## Que Se Agrego\n\n- `package.json` con scripts para Vite build, ESLint y publicacion de la extension.\n- `extensionrc.json` con la fuente del manifiesto de la extension.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` con `defineRunner`, un runner de pagina y un runner de widget.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` como pagina inicial de configuracion.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` como widget inicial del pedido.\n- `__SOURCE_ROOT__/i18n/` con archivos JSON de mensajes compartidos.\n- `__SOURCE_ROOT__/sandbox/tests/` con pruebas iniciales unit, browser y e2e.\n- `vitest.config.ts`, `vitest.config.browser.ts` y `vitest.config.playwright.ts` para ejecutar pruebas.\n- `scripts/publish-extension.mjs` para crear `dist/extension.zip` y publicar el modulo de integracion por RetailCRM API.\n- `scripts/serve-extension.mjs` para servir manifest, script y stylesheet compilados durante las pruebas e2e.\n- `AGENTS.md` si las instrucciones para agentes estaban activadas durante init.\n\n## Sustituya Los Valores Genericos\n\nRevise estos valores generados antes de usar el proyecto en una integracion real:\n\n- Codigo de extension en `extensionrc.json`: `retailcrm-extension-frontend`.\n- Nombre de extension en `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Codigo de pagina: `__PAGE_CODE__`.\n- Descriptor de pagina en `extensionrc.json`: mantenga `pages[]` como objeto con `code`, `menu` y `menuItemTitle`; la forma de cadena no sirve para publicar por la API RetailCRM.\n- Target del widget: `__WIDGET_TARGET__`.\n- Controles de ejemplo y datos ficticios en `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Acciones toolbar de ejemplo y datos ficticios del pedido en `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Mensajes compartidos en `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nLa pagina y el widget generados son intencionalmente genericos. Mantenga la estructura que necesite, pero sustituya etiquetas, campos y datos ficticios por comportamiento real del producto.\n\n## Nombres De Archivos Vue\n\n`SettingsPage.vue` y `OrderCommonAfterWidget.vue` son nombres iniciales genericos. En codigo de producto, renombre los archivos Vue segun la funcion que cumplen en la extension y actualice los imports en `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nEjemplos del repositorio de extensiones RetailCRM:\n\n- `ReturnsPage.vue` es una pagina completa de gestion de devoluciones.\n- `TasksPage.vue` es una pagina de lista o espacio de trabajo de tareas.\n- `SummaryPage.vue` es una pagina de resumen o dashboard.\n- `RecordToCalendlyWidget.vue` es un widget enfocado en un escenario.\n\nUse la misma idea para su codigo: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue` u otro nombre que describa el escenario real.\n\n## Comandos\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ test:unit\n__PACKAGE_MANAGER_RUN__ test:browser\n__PACKAGE_MANAGER_RUN__ test:e2e\n__PACKAGE_MANAGER_RUN__ serve:extension\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Pruebas\n\n- `__PACKAGE_MANAGER_RUN__ test:unit` ejecuta pruebas unitarias rapidas sin navegador.\n- `__PACKAGE_MANAGER_RUN__ test:browser` ejecuta la pagina y el widget iniciales en Chromium mediante Vitest Browser.\n- `__PACKAGE_MANAGER_RUN__ test:e2e` compila la extension, inicia la sandbox app y el servidor local de extension, luego comprueba la extension con Playwright.\n- `__PACKAGE_MANAGER_RUN__ serve:extension` inicia `http://127.0.0.1:4175` despues de compilar. Las pruebas construyen el manifest URL concreto como `http://127.0.0.1:4175/extension/<uuid>`.\n\nAntes del primer lanzamiento browser/e2e, instale Chromium si hace falta:\n\n```bash\n__PACKAGE_MANAGER_RUN__ test:browsers:install\n```\n\n## Publicacion\n\nCree `.env` en la raiz del proyecto cuando quiera que `publish-extension` actualice RetailCRM:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nEjecute `__PACKAGE_MANAGER_RUN__ build` antes de publicar. El modo archive-only crea `dist/extension.zip` sin enviar peticiones API.\n\nPara comprobar localmente en CRM, `MODULE_URL` debe apuntar a un dev/static server. `__PACKAGE_MANAGER_RUN__ serve:extension`\ninicia ese servidor local para el build actual de `dist` y resuelve `/extension/<uuid>`,\n`/extension/<uuid>/script` y `/extension/<uuid>/stylesheet` desde `extensionrc.json`.\n`publish-extension` registra estas URL en CRM, pero no arranca ese servidor.\n";
|
|
2159
2159
|
const readmeRuRUTemplate = "# Фронтенд расширения RetailCRM\n\nПроект создан командой `embed-ui init`.\n\n## Что Добавлено\n\n- `package.json` со скриптами для сборки Vite, ESLint и публикации расширения.\n- `extensionrc.json` с исходным описанием манифеста расширения.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` с `defineRunner`, одним runner страницы и одним runner виджета.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` как стартовая страница настроек.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` как стартовый виджет заказа.\n- `__SOURCE_ROOT__/i18n/` с общими JSON-файлами переводов.\n- `__SOURCE_ROOT__/sandbox/tests/` со стартовыми unit, browser и e2e тестами.\n- `vitest.config.ts`, `vitest.config.browser.ts` и `vitest.config.playwright.ts` для запуска тестов.\n- `scripts/publish-extension.mjs` для создания `dist/extension.zip` и публикации интеграционного модуля через RetailCRM API.\n- `scripts/serve-extension.mjs` для отдачи собранных manifest, script и stylesheet расширения во время e2e-тестов.\n- `AGENTS.md`, если при инициализации были включены инструкции для агентов.\n\n## Замените Generic Значения\n\nПеред использованием проекта в реальной интеграции проверьте сгенерированные общие значения:\n\n- Код расширения в `extensionrc.json`: `retailcrm-extension-frontend`.\n- Название расширения в `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Код страницы: `__PAGE_CODE__`.\n- Описание страницы в `extensionrc.json`: `pages[]` должен оставаться объектом с `code`, `menu` и `menuItemTitle`; строковая форма не подходит для публикации через RetailCRM API.\n- Цель виджета: `__WIDGET_TARGET__`.\n- Демонстрационные контролы и ненастоящие данные в `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Демонстрационные toolbar-действия и ненастоящие данные заказа в `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Общие сообщения в `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nСгенерированные страница и виджет намеренно сделаны универсальными. Оставьте нужную структуру, но замените примерные подписи, поля и ненастоящие данные на реальное поведение продукта.\n\n## Имена Vue-Файлов\n\n`SettingsPage.vue` и `OrderCommonAfterWidget.vue` — универсальные стартовые имена. В продуктовом коде переименуйте Vue-файлы по роли, которую они выполняют в расширении, и обновите импорты в `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nПримеры из репозитория расширений RetailCRM:\n\n- `ReturnsPage.vue` — полноценная страница управления возвратами.\n- `TasksPage.vue` — страница списка задач или рабочей области задач.\n- `SummaryPage.vue` — страница сводки или дашборда.\n- `RecordToCalendlyWidget.vue` — сфокусированный виджет под один сценарий.\n\nИспользуйте тот же принцип: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue` или другое имя, которое описывает реальный сценарий.\n\n## Команды\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ test:unit\n__PACKAGE_MANAGER_RUN__ test:browser\n__PACKAGE_MANAGER_RUN__ test:e2e\n__PACKAGE_MANAGER_RUN__ serve:extension\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Тестирование\n\n- `__PACKAGE_MANAGER_RUN__ test:unit` проверяет быстрые unit-тесты без браузера.\n- `__PACKAGE_MANAGER_RUN__ test:browser` запускает стартовую страницу и виджет в Chromium через Vitest Browser.\n- `__PACKAGE_MANAGER_RUN__ test:e2e` собирает расширение, поднимает sandbox-приложение и локальный extension server, затем проверяет расширение через Playwright.\n- `__PACKAGE_MANAGER_RUN__ serve:extension` после сборки запускает `http://127.0.0.1:4175`. Тесты собирают конкретный manifest URL как `http://127.0.0.1:4175/extension/<uuid>`.\n\nПеред первым browser/e2e запуском может потребоваться установить Chromium:\n\n```bash\n__PACKAGE_MANAGER_RUN__ test:browsers:install\n```\n\n## Публикация\n\nСоздайте `.env` в корне проекта, когда потребуется обновлять RetailCRM через `publish-extension`:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nПеред публикацией выполните `__PACKAGE_MANAGER_RUN__ build`. Режим archive-only создает `dist/extension.zip` без API-запросов.\n\nДля локальной проверки в CRM `MODULE_URL` должен указывать на dev/static server. `__PACKAGE_MANAGER_RUN__ serve:extension`\nзапускает такой локальный сервер для текущей сборки `dist` и резолвит `/extension/<uuid>`,\n`/extension/<uuid>/script` и `/extension/<uuid>/stylesheet` из `extensionrc.json`.\n`publish-extension` регистрирует эти URL в CRM, но сам dev-server не запускает.\n";
|
|
2160
2160
|
const sandboxBrowserTestTemplate = "import type { SandboxWorkerRuntime } from '@retailcrm/embed-ui-v1-sandbox/automation/browser'\n\nimport { afterEach, expect, test } from 'vitest'\nimport { fireEvent, screen } from '@testing-library/dom'\n\nimport { createExtensionSourceWorker } from '@retailcrm/embed-ui-v1-sandbox/automation/browser'\nimport { createSandboxWorkerRuntime } from '@retailcrm/embed-ui-v1-sandbox/automation/browser'\n\nlet runtime: SandboxWorkerRuntime | null = null\n\nafterEach(async () => {\n await runtime?.teardown()\n runtime = null\n document.body.innerHTML = ''\n window.history.replaceState(null, '', '/')\n})\n\ntest('opens generated settings page', async () => {\n runtime = await createRuntime()\n\n await runtime.runPage('__PAGE_CODE__')\n\n expect(await screen.findByRole('heading', { name: 'Настройки расширения' })).toBeInstanceOf(HTMLElement)\n expect(screen.getByRole('button', { name: 'Сохранить' })).toBeInstanceOf(HTMLButtonElement)\n})\n\ntest('opens generated order widget sidebar', async () => {\n runtime = await createRuntime()\n\n await runtime.runWidget('__WIDGET_TARGET__')\n\n const openSidebar = await screen.findByRole('button', { name: 'Подготовить связь' })\n\n fireEvent.click(openSidebar)\n\n expect(await screen.findByRole('dialog')).toBeInstanceOf(HTMLElement)\n expect(screen.getByText('Связь по заказу')).toBeInstanceOf(HTMLElement)\n})\n\nconst createRuntime = async (): Promise<SandboxWorkerRuntime> => {\n const sourceWorker = createExtensionSourceWorker(\n new URL('/__SOURCE_ROOT__/endpoint/endpoint.worker.ts', window.location.href)\n )\n\n return createSandboxWorkerRuntime({\n fixture: 'order-basic',\n ready: sourceWorker.ready,\n worker: sourceWorker.worker,\n })\n}\n";
|
|
2161
|
-
const sandboxE2eTestTemplate =
|
|
2162
|
-
import path from 'node:path'
|
|
2163
|
-
|
|
2164
|
-
import { expect, test } from '@playwright/test'
|
|
2165
|
-
|
|
2166
|
-
import {
|
|
2167
|
-
createSandboxPagePath,
|
|
2168
|
-
readSandboxSnapshot,
|
|
2169
|
-
} from '@retailcrm/embed-ui-v1-sandbox/automation/playwright'
|
|
2170
|
-
|
|
2171
|
-
type ExtensionConfig = {
|
|
2172
|
-
pages: Array<{ code: string }>
|
|
2173
|
-
targets: string[]
|
|
2174
|
-
uuid: string
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
|
-
const extensionBaseURL = process.env.SANDBOX_EXTENSION_URL || 'http://127.0.0.1:4175/extension/'
|
|
2178
|
-
const extensionrc = JSON.parse(
|
|
2179
|
-
fs.readFileSync(path.resolve(process.cwd(), 'extensionrc.json'), 'utf8')
|
|
2180
|
-
) as ExtensionConfig
|
|
2181
|
-
const extensionUrl = new URL(extensionrc.uuid, extensionBaseURL).href
|
|
2182
|
-
const [pageDescriptor] = extensionrc.pages
|
|
2183
|
-
const [target] = extensionrc.targets
|
|
2184
|
-
|
|
2185
|
-
test('loads generated settings page extension and saves settings', async ({ page }) => {
|
|
2186
|
-
await page.goto(createSandboxPagePath({
|
|
2187
|
-
extensionUrl,
|
|
2188
|
-
manifestUrl: extensionUrl,
|
|
2189
|
-
pageCode: pageDescriptor.code,
|
|
2190
|
-
targets: [target],
|
|
2191
|
-
}))
|
|
2192
|
-
|
|
2193
|
-
await expect(page).toHaveURL(/mode=page/u)
|
|
2194
|
-
await expect(page).toHaveURL(new RegExp(\`pageCode=\${pageDescriptor.code}\`, 'u'))
|
|
2195
|
-
await expect(page.getByRole('heading', { name: 'Настройки расширения' })).toBeVisible()
|
|
2196
|
-
await expect(page.locator('svg[class*="settings-page-addon__icon"]')).toHaveCSS('width', '24px')
|
|
2197
|
-
await expect(page.locator('svg[class*="settings-page-addon__icon"]')).toHaveCSS('height', '24px')
|
|
2198
|
-
await expect(page.getByRole('button', { name: 'Сохранить' })).toBeVisible()
|
|
2199
|
-
await expect(page.getByLabel('Название помощника')).toHaveValue('Order follow-up')
|
|
2200
|
-
|
|
2201
|
-
await page.getByLabel('Название помощника').fill('E2E assistant')
|
|
2202
|
-
await page.getByRole('button', { name: 'Сохранить' }).click()
|
|
2203
|
-
|
|
2204
|
-
await expect(page.locator('body')).toContainText('Настройки сохранены')
|
|
2205
|
-
|
|
2206
|
-
const snapshot = await readSandboxSnapshot(page)
|
|
2207
|
-
|
|
2208
|
-
expect(snapshot.host.http.every(record => record.response.status === 200)).toBe(true)
|
|
2209
|
-
})
|
|
2210
|
-
`;
|
|
2161
|
+
const sandboxE2eTestTemplate = "import fs from 'node:fs'\nimport path from 'node:path'\n\nimport { expect, test } from '@playwright/test'\n\nimport {\n createSandboxPagePath,\n readSandboxSnapshot,\n} from '@retailcrm/embed-ui-v1-sandbox/automation/playwright'\n\ntype ExtensionConfig = {\n pages: Array<{ code: string }>\n targets: string[]\n uuid: string\n}\n\nconst extensionBaseURL = process.env.SANDBOX_EXTENSION_URL?.trim()\nconst extensionrc = JSON.parse(\n fs.readFileSync(path.resolve(process.cwd(), 'extensionrc.json'), 'utf8')\n) as ExtensionConfig\nconst extensionUrl = extensionBaseURL\n ? new URL(extensionrc.uuid, extensionBaseURL).href\n : ''\nconst [pageDescriptor] = extensionrc.pages\nconst [target] = extensionrc.targets\nconst missingExtensionUrlMessage = 'Fill SANDBOX_EXTENSION_URL in .env.sandbox before running starter.e2e.ts.'\n\nif (!extensionBaseURL) {\n console.warn(`[sandbox:e2e] ${missingExtensionUrlMessage}`)\n}\n\ntest.skip(\n !extensionBaseURL,\n missingExtensionUrlMessage\n)\n\ntest('loads generated settings page extension and saves settings', async ({ page }) => {\n await page.goto(createSandboxPagePath({\n extensionUrl,\n manifestUrl: extensionUrl,\n pageCode: pageDescriptor.code,\n targets: [target],\n }))\n\n await expect(page).toHaveURL(/mode=page/u)\n await expect(page).toHaveURL(new RegExp(`pageCode=${pageDescriptor.code}`, 'u'))\n await expect(page.getByRole('heading', { name: 'Настройки расширения' })).toBeVisible()\n await expect(page.locator('svg[class*=\"settings-page-addon__icon\"]')).toHaveCSS('width', '24px')\n await expect(page.locator('svg[class*=\"settings-page-addon__icon\"]')).toHaveCSS('height', '24px')\n await expect(page.getByRole('button', { name: 'Сохранить' })).toBeVisible()\n await expect(page.getByLabel('Название помощника')).toHaveValue('Order follow-up')\n\n await page.getByLabel('Название помощника').fill('E2E assistant')\n await page.getByRole('button', { name: 'Сохранить' }).click()\n\n await expect(page.locator('body')).toContainText('Настройки сохранены')\n\n const snapshot = await readSandboxSnapshot(page)\n\n expect(snapshot.host.http.every(record => record.response.status === 200)).toBe(true)\n})\n";
|
|
2211
2162
|
const sandboxUnitTestTemplate = "import { describe, expect, test } from 'vitest'\n\nimport extensionrc from '../../../../extensionrc.json'\n\ndescribe('extension manifest', () => {\n test('contains generated page and widget target', () => {\n expect(extensionrc.pages).toEqual(\n expect.arrayContaining([\n expect.objectContaining({ code: '__PAGE_CODE__' }),\n ])\n )\n\n expect(extensionrc.targets).toContain('__WIDGET_TARGET__')\n expect(extensionrc.runner).toBe('worker')\n expect(extensionrc.entrypointType).toBe('script')\n })\n})\n";
|
|
2212
2163
|
const serveScriptTemplate = `#!/usr/bin/env node
|
|
2213
2164
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retailcrm/embed-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.30-alpha.
|
|
4
|
+
"version": "0.9.30-alpha.2",
|
|
5
5
|
"description": "API and components for creating RetailCRM UI extensions",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -67,10 +67,10 @@
|
|
|
67
67
|
"@omnicajs/symfony-router": "^1.0.0",
|
|
68
68
|
"@omnicajs/vue-remote": "^0.2.26",
|
|
69
69
|
"@remote-ui/rpc": "^1.4.5",
|
|
70
|
-
"@retailcrm/embed-ui-v1-components": "^0.9.30-alpha.
|
|
71
|
-
"@retailcrm/embed-ui-v1-contexts": "^0.9.30-alpha.
|
|
72
|
-
"@retailcrm/embed-ui-v1-endpoint": "^0.9.30-alpha.
|
|
73
|
-
"@retailcrm/embed-ui-v1-types": "^0.9.30-alpha.
|
|
70
|
+
"@retailcrm/embed-ui-v1-components": "^0.9.30-alpha.2",
|
|
71
|
+
"@retailcrm/embed-ui-v1-contexts": "^0.9.30-alpha.2",
|
|
72
|
+
"@retailcrm/embed-ui-v1-endpoint": "^0.9.30-alpha.2",
|
|
73
|
+
"@retailcrm/embed-ui-v1-types": "^0.9.30-alpha.2",
|
|
74
74
|
"yargs": "^17.7.2"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@modulify/conventional-release": "^0.1.3",
|
|
81
81
|
"@modulify/pkg": "^1.0.1",
|
|
82
82
|
"@omnicajs/eslint-plugin-dependencies": "^0.0.2",
|
|
83
|
-
"@retailcrm/embed-ui-v1-testing": "^0.9.30-alpha.
|
|
83
|
+
"@retailcrm/embed-ui-v1-testing": "^0.9.30-alpha.2",
|
|
84
84
|
"@types/node": "^22.19.2",
|
|
85
85
|
"@types/semver": "^7.7.1",
|
|
86
86
|
"@types/yargs": "^17.0.35",
|