Groundwork for internationalization of designer components

This commit is contained in:
Sipke Schoorstra 2021-07-15 12:40:36 +02:00
parent 42d47386ed
commit a5add7f52a
25 changed files with 496 additions and 90 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@elsa-workflows/elsa-workflows-studio",
"version": "2.1.3",
"version": "2.1.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -27,6 +27,14 @@
"js-tokens": "^4.0.0"
}
},
"@babel/runtime": {
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz",
"integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"@csstools/convert-colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
@ -2391,6 +2399,19 @@
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg=="
},
"i18next": {
"version": "20.3.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-20.3.3.tgz",
"integrity": "sha512-tx9EUhHeaipvZ5pFLTaN9Xdm5Ssal774MpujaTA1Wv/ST/1My5SnoBmliY1lOpyEP5Z51Dq1gXifk/y4Yt3agQ==",
"requires": {
"@babel/runtime": "^7.12.0"
}
},
"i18next-wc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/i18next-wc/-/i18next-wc-1.1.0.tgz",
"integrity": "sha512-CL1KYATH6MViR4wXRxXx3rRvlHh5hHD0GTzy5DpxrDlmDmzJMjHoCqd5HCWKmdLrUkFtdTkfNT0hARpsyJ8OKA=="
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -4083,6 +4104,11 @@
}
}
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
},
"regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",

View file

@ -51,6 +51,8 @@
"dagre-d3": "^0.6.4",
"el-transition": "^0.0.7",
"eslint": "7.29.0",
"i18next": "^20.3.3",
"i18next-wc": "^1.1.0",
"js-event-bus": "^1.1.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",

View file

@ -19,6 +19,7 @@ import { ToastNotificationOptions } from "./components/shared/elsa-toast-notific
import { WebhookDefinition } from "./models/webhook";
export namespace Components {
interface ElsaActivityEditorModal {
"culture": string;
}
interface ElsaActivityPickerModal {
}
@ -32,6 +33,7 @@ export namespace Components {
"propertyModel": ActivityDefinitionProperty;
}
interface ElsaConfirmDialog {
"culture": string;
"hide": () => Promise<void>;
"show": (caption: string, message: string) => Promise<boolean>;
}
@ -160,8 +162,10 @@ export namespace Components {
"propertyModel": ActivityDefinitionProperty;
}
interface ElsaStudioHome {
"culture": string;
}
interface ElsaStudioRoot {
"culture": string;
"monacoLibPath": string;
"serverUrl": string;
}
@ -171,6 +175,7 @@ export namespace Components {
"serverUrl": string;
}
interface ElsaStudioWebhookDefinitionsList {
"culture": string;
"history": RouterHistory;
"serverUrl": string;
}
@ -179,11 +184,13 @@ export namespace Components {
"serverUrl": string;
}
interface ElsaStudioWorkflowDefinitionsEdit {
"culture": string;
"match": MatchResults;
"monacoLibPath": string;
"serverUrl": string;
}
interface ElsaStudioWorkflowDefinitionsList {
"culture": string;
"history": RouterHistory;
"serverUrl": string;
}
@ -229,6 +236,7 @@ export namespace Components {
interface ElsaWorkflowDefinitionEditorNotifications {
}
interface ElsaWorkflowDefinitionEditorScreen {
"culture": string;
"exportWorkflow": () => Promise<void>;
"getServerUrl": () => Promise<string>;
"getWorkflowDefinitionId": () => Promise<string>;
@ -238,6 +246,7 @@ export namespace Components {
"workflowDefinitionId": string;
}
interface ElsaWorkflowDefinitionsListScreen {
"culture": string;
"history"?: RouterHistory;
"serverUrl": string;
}
@ -264,6 +273,7 @@ export namespace Components {
"workflowInstanceId": string;
}
interface ElsaWorkflowPublishButton {
"culture": string;
"publishing": boolean;
"workflowDefinition": WorkflowDefinition;
}
@ -625,6 +635,7 @@ declare global {
}
declare namespace LocalJSX {
interface ElsaActivityEditorModal {
"culture"?: string;
}
interface ElsaActivityPickerModal {
}
@ -638,6 +649,7 @@ declare namespace LocalJSX {
"propertyModel"?: ActivityDefinitionProperty;
}
interface ElsaConfirmDialog {
"culture"?: string;
}
interface ElsaContextMenu {
"history"?: RouterHistory;
@ -772,8 +784,10 @@ declare namespace LocalJSX {
"propertyModel"?: ActivityDefinitionProperty;
}
interface ElsaStudioHome {
"culture"?: string;
}
interface ElsaStudioRoot {
"culture"?: string;
"monacoLibPath"?: string;
"serverUrl"?: string;
}
@ -783,6 +797,7 @@ declare namespace LocalJSX {
"serverUrl"?: string;
}
interface ElsaStudioWebhookDefinitionsList {
"culture"?: string;
"history"?: RouterHistory;
"serverUrl"?: string;
}
@ -791,11 +806,13 @@ declare namespace LocalJSX {
"serverUrl"?: string;
}
interface ElsaStudioWorkflowDefinitionsEdit {
"culture"?: string;
"match"?: MatchResults;
"monacoLibPath"?: string;
"serverUrl"?: string;
}
interface ElsaStudioWorkflowDefinitionsList {
"culture"?: string;
"history"?: RouterHistory;
"serverUrl"?: string;
}
@ -836,12 +853,14 @@ declare namespace LocalJSX {
interface ElsaWorkflowDefinitionEditorNotifications {
}
interface ElsaWorkflowDefinitionEditorScreen {
"culture"?: string;
"monacoLibPath"?: string;
"onWorkflowSaved"?: (event: CustomEvent<WorkflowDefinition>) => void;
"serverUrl"?: string;
"workflowDefinitionId"?: string;
}
interface ElsaWorkflowDefinitionsListScreen {
"culture"?: string;
"history"?: RouterHistory;
"serverUrl"?: string;
}
@ -865,6 +884,7 @@ declare namespace LocalJSX {
"workflowInstanceId"?: string;
}
interface ElsaWorkflowPublishButton {
"culture"?: string;
"onExportClicked"?: (event: CustomEvent<any>) => void;
"onImportClicked"?: (event: CustomEvent<File>) => void;
"onPublishClicked"?: (event: CustomEvent<any>) => void;

View file

@ -1,4 +1,9 @@
import {Component, h, Prop, getAssetPath} from '@stencil/core';
import {Component, getAssetPath, h, Prop} from '@stencil/core';
import 'i18next-wc';
import {GetIntlMessage, IntlMessage} from "../../../i18n/intl-message";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
import {i18n} from "i18next";
@Component({
tag: 'elsa-studio-home',
@ -7,36 +12,42 @@ import {Component, h, Prop, getAssetPath} from '@stencil/core';
})
export class ElsaStudioHome {
@Prop() culture: string;
private i18next: i18n;
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
}
render() {
const visualPath = getAssetPath('./assets/undraw_breaking_barriers_vnf3.svg');
const IntlMessage = GetIntlMessage(this.i18next);
return (
<div class="elsa-relative elsa-bg-gray-800 elsa-overflow-hidden elsa-h-screen">
<main class="elsa-mt-16 sm:elsa-mt-24">
<div class="elsa-mx-auto elsa-max-w-7xl">
<div class="lg:elsa-grid lg:elsa-grid-cols-12 lg:elsa-gap-8">
<div class="elsa-px-4 sm:elsa-px-6 sm:elsa-text-center md:elsa-max-w-2xl md:elsa-mx-auto lg:elsa-col-span-6 lg:elsa-text-left lg:flex lg:elsa-items-center">
<div>
<h1 class="elsa-mt-4 elsa-text-4xl elsa-tracking-tight elsa-font-extrabold elsa-text-white sm:elsa-mt-5 sm:elsa-leading-none lg:elsa-mt-6 lg:elsa-text-5xl xl:elsa-text-6xl">
<span class="md:elsa-block">Welcome to</span>
<span class="elsa-text-teal-400 md:elsa-block">Elsa Workflows</span> <span>2.0</span>
</h1>
<p class="elsa-mt-3 elsa-text-base elsa-text-gray-300 sm:elsa-mt-5 sm:elsa-text-xl lg:elsa-text-lg xl:elsa-text-xl">
Use the dashboard app to manage all the things.
</p>
<main class="elsa-mt-16 sm:elsa-mt-24">
<div class="elsa-mx-auto elsa-max-w-7xl">
<div class="lg:elsa-grid lg:elsa-grid-cols-12 lg:elsa-gap-8">
<div class="elsa-px-4 sm:elsa-px-6 sm:elsa-text-center md:elsa-max-w-2xl md:elsa-mx-auto lg:elsa-col-span-6 lg:elsa-text-left lg:flex lg:elsa-items-center">
<div>
<h1 class="elsa-mt-4 elsa-text-4xl elsa-tracking-tight elsa-font-extrabold elsa-text-white sm:elsa-mt-5 sm:elsa-leading-none lg:elsa-mt-6 lg:elsa-text-5xl xl:elsa-text-6xl">
<span class="md:elsa-block"><IntlMessage label="Welcome" dangerous title="<span class='elsa-text-teal-400 md:elsa-block'>Elsa Workflows</span> <span>2.0</span>"/></span>
</h1>
<p class="elsa-mt-3 elsa-text-base elsa-text-gray-300 sm:elsa-mt-5 sm:elsa-text-xl lg:elsa-text-lg xl:elsa-text-xl">
<IntlMessage label="Tagline"/>
</p>
</div>
</div>
</div>
<div class="elsa-mt-16 sm:elsa-mt-24 lg:elsa-mt-0 lg:elsa-col-span-6">
<div class="sm:elsa-max-w-md sm:elsa-w-full sm:elsa-mx-auto sm:elsa-rounded-lg sm:elsa-overflow-hidden">
<div class="elsa-px-4 elsa-py-8 sm:elsa-px-10">
<img src={visualPath} alt="" width={400} />
<div class="elsa-mt-16 sm:elsa-mt-24 lg:elsa-mt-0 lg:elsa-col-span-6">
<div class="sm:elsa-max-w-md sm:elsa-w-full sm:elsa-mx-auto sm:elsa-rounded-lg sm:elsa-overflow-hidden">
<div class="elsa-px-4 elsa-py-8 sm:elsa-px-10">
<img src={visualPath} alt="" width={400}/>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</main>
</div>
);
}

View file

@ -0,0 +1,14 @@
export const resources = {
'en': {
'default': {
'Welcome': 'Welcome to {{title}}',
'Tagline': 'Use the dashboard app to manage all the things.'
}
},
'nl-NL': {
'default': {
'Welcome': 'Welkom bij {{title}}',
'Tagline': 'Gebruik het dashboard om alles te regelen.'
}
}
};

View file

@ -1,4 +1,8 @@
import {Component, h, Prop, getAssetPath} from '@stencil/core';
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
import {i18n} from "i18next";
import {GetIntlMessage} from "../../../i18n/intl-message";
@Component({
tag: 'elsa-studio-root',
@ -9,10 +13,17 @@ export class ElsaStudioRoot {
@Prop({attribute: 'server-url', reflect: true}) serverUrl: string;
@Prop({attribute: 'monaco-lib-path', reflect: true}) monacoLibPath: string;
@Prop({attribute: 'culture', reflect: true}) culture: string;
private i18next: i18n;
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
}
render() {
const serverUrl = this.serverUrl;
const culture = this.culture;
const monacoLibPath = this.monacoLibPath;
const logoPath = getAssetPath('./assets/logo.png');
@ -20,6 +31,8 @@ export class ElsaStudioRoot {
// const tunnelState: DashboardState = {
// serverUrl: serverUrl,
// };
const IntlMessage = GetIntlMessage(this.i18next);
return (
<div class="elsa-h-screen elsa-bg-gray-100">
@ -28,25 +41,28 @@ export class ElsaStudioRoot {
<div class="elsa-flex elsa-items-center elsa-justify-between elsa-h-16">
<div class="elsa-flex elsa-items-center">
<div class="elsa-flex-shrink-0">
<img class="elsa-h-8 elsa-w-8" src={logoPath} alt="Workflow"/>
<stencil-route-link url="/"><img class="elsa-h-8 elsa-w-8" src={logoPath} alt="Workflow"/></stencil-route-link>
</div>
<div class="hidden md:elsa-block">
<div class="elsa-ml-10 elsa-flex elsa-items-baseline elsa-space-x-4">
<stencil-route-link url="/workflow-definitions" anchorClass="elsa-text-gray-300 hover:elsa-bg-gray-700 hover:elsa-text-white elsa-px-3 elsa-py-2 elsa-rounded-md elsa-text-sm elsa-font-medium"
activeClass="elsa-text-white elsa-bg-gray-900">Workflow Definitions
activeClass="elsa-text-white elsa-bg-gray-900">
<IntlMessage label="WorkflowDefinitions"/>
</stencil-route-link>
<stencil-route-link url="/workflow-instances" anchorClass="elsa-text-gray-300 hover:elsa-bg-gray-700 hover:elsa-text-white elsa-px-3 elsa-py-2 elsa-rounded-md elsa-text-sm elsa-font-medium"
activeClass="elsa-text-white elsa-bg-gray-900">Workflow Instances
activeClass="elsa-text-white elsa-bg-gray-900">
<IntlMessage label="WorkflowInstances"/>
</stencil-route-link>
<stencil-route-link url="/workflow-registry" anchorClass="elsa-text-gray-300 hover:elsa-bg-gray-700 hover:elsa-text-white elsa-px-3 elsa-py-2 elsa-rounded-md elsa-text-sm elsa-font-medium"
activeClass="elsa-text-white elsa-bg-gray-900">Workflow Registry
activeClass="elsa-text-white elsa-bg-gray-900">
<IntlMessage label="WorkflowRegistry"/>
</stencil-route-link>
{/*<stencil-route-link url="/custom-activities" class="elsa-text-gray-300 hover:elsa-bg-gray-700 hover:elsa-text-white elsa-px-3 elsa-py-2 elsa-rounded-md elsa-text-sm elsa-font-medium">Custom Activities</stencil-route-link>*/}
<stencil-route-link url="/webhook-definitions" anchorClass="elsa-text-gray-300 hover:elsa-bg-gray-700 hover:elsa-text-white elsa-px-3 elsa-py-2 elsa-rounded-md elsa-text-sm elsa-font-medium"
activeClass="elsa-text-white elsa-bg-gray-900">Webhook Definitions
activeClass="elsa-text-white elsa-bg-gray-900">
<IntlMessage label="WebhookDefinitions"/>
</stencil-route-link>
{/*<stencil-route-link url="/custom-activities" class="elsa-text-gray-300 hover:elsa-bg-gray-700 hover:elsa-text-white elsa-px-3 elsa-py-2 elsa-rounded-md elsa-text-sm elsa-font-medium">Custom Activities</stencil-route-link>*/}
</div>
</div>
</div>
@ -58,15 +74,15 @@ export class ElsaStudioRoot {
{/*<Tunnel.Provider state={tunnelState}>*/}
<stencil-router>
<stencil-route-switch scrollTopOffset={0}>
<stencil-route url="/" component="elsa-studio-home" exact={true}/>
<stencil-route url="/workflow-registry" component="elsa-studio-workflow-registry" componentProps={{'serverUrl': serverUrl}} exact={true}/>
<stencil-route url="/workflow-registry/:id" component="elsa-studio-workflow-blueprint-view" componentProps={{'serverUrl': serverUrl}}/>
<stencil-route url="/workflow-definitions" component="elsa-studio-workflow-definitions-list" componentProps={{'serverUrl': serverUrl}} exact={true}/>
<stencil-route url="/workflow-definitions/:id" component="elsa-studio-workflow-definitions-edit" componentProps={{'serverUrl': serverUrl, 'monacoLibPath': monacoLibPath}}/>
<stencil-route url="/workflow-instances" component="elsa-studio-workflow-instances-list" componentProps={{'serverUrl': serverUrl}} exact={true}/>
<stencil-route url="/workflow-instances/:id" component="elsa-studio-workflow-instances-view" componentProps={{'serverUrl': serverUrl}}/>
<stencil-route url="/webhook-definitions" component="elsa-studio-webhook-definitions-list" componentProps={{'serverUrl': serverUrl}} exact={true}/>
<stencil-route url="/webhook-definitions/:id" component="elsa-studio-webhook-definitions-edit" componentProps={{'serverUrl': serverUrl}}/>
<stencil-route url="/" component="elsa-studio-home" exact={true} componentProps={{culture: culture}}/>
<stencil-route url="/workflow-registry" component="elsa-studio-workflow-registry" componentProps={{'serverUrl': serverUrl, culture: culture}} exact={true}/>
<stencil-route url="/workflow-registry/:id" component="elsa-studio-workflow-blueprint-view" componentProps={{'serverUrl': serverUrl, culture: culture}}/>
<stencil-route url="/workflow-definitions" component="elsa-studio-workflow-definitions-list" componentProps={{'serverUrl': serverUrl, culture: culture}} exact={true}/>
<stencil-route url="/workflow-definitions/:id" component="elsa-studio-workflow-definitions-edit" componentProps={{'serverUrl': serverUrl, culture: culture, 'monacoLibPath': monacoLibPath}}/>
<stencil-route url="/workflow-instances" component="elsa-studio-workflow-instances-list" componentProps={{'serverUrl': serverUrl, culture: culture}} exact={true}/>
<stencil-route url="/workflow-instances/:id" component="elsa-studio-workflow-instances-view" componentProps={{'serverUrl': serverUrl, culture: culture}}/>
<stencil-route url="/webhook-definitions" component="elsa-studio-webhook-definitions-list" componentProps={{'serverUrl': serverUrl, culture: culture}} exact={true}/>
<stencil-route url="/webhook-definitions/:id" component="elsa-studio-webhook-definitions-edit" componentProps={{'serverUrl': serverUrl, culture: culture}}/>
</stencil-route-switch>
</stencil-router>
{/*</Tunnel.Provider>*/}

View file

@ -0,0 +1,18 @@
export const resources = {
'en': {
default: {
'WorkflowDefinitions': 'Workflow Definitions',
'WorkflowInstances': 'Workflow Instances',
'WorkflowRegistry': 'Workflow Registry',
'WebhookDefinitions': 'Webhook Definitions',
}
},
'nl-NL': {
default: {
'WorkflowDefinitions': 'Workflow Definities',
'WorkflowInstances': 'Workflows',
'WorkflowRegistry': 'Workflow Register',
'WebhookDefinitions': 'Webhook Definities',
}
}
};

View file

@ -1,5 +1,9 @@
import {Component, h, Prop, State} from '@stencil/core';
import {RouterHistory} from "@stencil/router";
import 'i18next-wc';
import {IntlMessage} from "../../../i18n/intl-message";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
@Component({
tag: 'elsa-studio-webhook-definitions-list',
@ -8,6 +12,11 @@ import {RouterHistory} from "@stencil/router";
export class ElsaStudioWebhookDefinitionsList {
@Prop() history: RouterHistory;
@Prop() serverUrl: string;
@Prop() culture: string;
async componentWillLoad() {
await loadTranslations(this.culture, resources);
}
render() {
return (
@ -15,13 +24,13 @@ export class ElsaStudioWebhookDefinitionsList {
<div class="elsa-border-b elsa-border-gray-200 elsa-px-4 elsa-py-4 sm:elsa-flex sm:elsa-items-center sm:elsa-justify-between sm:elsa-px-6 lg:elsa-px-8 elsa-bg-white">
<div class="elsa-flex-1 elsa-min-w-0">
<h1 class="elsa-text-lg elsa-font-medium elsa-leading-6 elsa-text-gray-900 sm:elsa-truncate">
Webhook Definitions
<IntlMessage label="Title"/>
</h1>
</div>
<div class="elsa-mt-4 elsa-flex sm:elsa-mt-0 sm:elsa-ml-4">
<stencil-route-link url="/webhook-definitions/new"
class="elsa-order-0 elsa-inline-flex elsa-items-center elsa-px-4 elsa-py-2 elsa-border elsa-border-transparent elsa-shadow-sm elsa-text-sm elsa-font-medium elsa-rounded-md elsa-text-white elsa-bg-blue-600 hover:elsa-bg-blue-700 focus:elsa-outline-none focus:elsa-ring-2 focus:elsa-ring-offset-2 focus:elsa-ring-blue-500 sm:elsa-order-1 sm:elsa-ml-3">
Create Webhook
<IntlMessage label="CreateButton"/>
</stencil-route-link>
</div>
</div>

View file

@ -0,0 +1,14 @@
export const resources = {
'en': {
default: {
'Title': 'Webhook Definitions',
'CreateButton': 'Create Webhook'
}
},
'nl-NL': {
default: {
'Title': 'Webhook Definitie',
'CreateButton': 'Maak Webhook'
}
}
};

View file

@ -9,6 +9,7 @@ export class ElsaStudioWorkflowDefinitionsEdit {
@Prop() match: MatchResults;
@Prop() serverUrl: string;
@Prop() monacoLibPath: string;
@Prop() culture: string;
id?: string;
@ -25,7 +26,7 @@ export class ElsaStudioWorkflowDefinitionsEdit {
const id = this.id;
return <div>
<elsa-workflow-definition-editor-screen server-url={this.serverUrl} workflow-definition-id={id} monaco-lib-path={this.monacoLibPath}/>
<elsa-workflow-definition-editor-screen server-url={this.serverUrl} workflow-definition-id={id} monaco-lib-path={this.monacoLibPath} culture={this.culture}/>
</div>;
}
}

View file

@ -1,5 +1,10 @@
import {Component, h, Prop, State} from '@stencil/core';
import {RouterHistory} from "@stencil/router";
import 'i18next-wc';
import {GetIntlMessage, IntlMessage} from "../../../i18n/intl-message";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
import {i18n} from "i18next";
@Component({
tag: 'elsa-studio-workflow-definitions-list',
@ -8,25 +13,33 @@ import {RouterHistory} from "@stencil/router";
export class ElsaStudioWorkflowDefinitionsList {
@Prop() history: RouterHistory;
@Prop() serverUrl: string;
@Prop() culture: string;
private i18next: i18n;
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
}
render() {
const IntlMessage = GetIntlMessage(this.i18next);
return (
<div>
<div class="elsa-border-b elsa-border-gray-200 elsa-px-4 elsa-py-4 sm:elsa-flex sm:elsa-items-center sm:elsa-justify-between sm:elsa-px-6 lg:elsa-px-8 elsa-bg-white">
<div class="elsa-flex-1 elsa-min-w-0">
<h1 class="elsa-text-lg elsa-font-medium elsa-leading-6 elsa-text-gray-900 sm:elsa-truncate">
Workflow Definitions
<IntlMessage label="Title"/>
</h1>
</div>
<div class="elsa-mt-4 elsa-flex sm:elsa-mt-0 sm:elsa-ml-4">
<stencil-route-link url="/workflow-definitions/new"
class="elsa-order-0 elsa-inline-flex elsa-items-center elsa-px-4 elsa-py-2 elsa-border elsa-border-transparent elsa-shadow-sm elsa-text-sm elsa-font-medium elsa-rounded-md elsa-text-white elsa-bg-blue-600 hover:elsa-bg-blue-700 focus:elsa-outline-none focus:elsa-ring-2 focus:elsa-ring-offset-2 focus:elsa-ring-blue-500 sm:elsa-order-1 sm:elsa-ml-3">
Create Workflow
<IntlMessage label="CreateButton"/>
</stencil-route-link>
</div>
</div>
<elsa-workflow-definitions-list-screen history={this.history} serverUrl={this.serverUrl} />
<elsa-workflow-definitions-list-screen history={this.history} serverUrl={this.serverUrl} culture={this.culture} />
</div>
);
}

View file

@ -0,0 +1,14 @@
export const resources = {
'en': {
default: {
'Title': 'Workflow Definitions',
'CreateButton': 'Create Workflow'
}
},
'nl-NL': {
default: {
'Title': 'Workflow Definities',
'CreateButton': 'Nieuwe Workflow'
}
}
};

View file

@ -0,0 +1,14 @@
import i18next from 'i18next';
export async function loadTranslations(language: string, resources: any, defaultNamespace?: string): Promise<any> {
const instance = i18next.createInstance();
await instance.init({
lng: language,
fallbackLng: "en",
resources: resources,
defaultNS: defaultNamespace || 'default',
debug: true
});
return instance;
}

View file

@ -0,0 +1,9 @@
import i18next, {i18n} from 'i18next';
import 'i18next-wc';
import {h} from "@stencil/core";
export const IntlMessage = (props) => (<intl-message { ...{i18next, ...props }} />);
export function GetIntlMessage(i18next: i18n){
return (props) => (<intl-message { ...{i18next, ...props }} />);
}

View file

@ -1,20 +1,24 @@
import {Component, Event, h, Host, State} from '@stencil/core';
import {Component, Event, h, Host, Prop, State} from '@stencil/core';
import {eventBus} from '../../../../services/event-bus';
import state from '../../../../utils/store';
import {ActivityDescriptor, ActivityModel, ActivityPropertyDescriptor, EventTypes, WorkflowStorageDescriptor} from "../../../../models";
import {propertyDisplayManager} from '../../../../services/property-display-manager';
import {checkBox, FormContext, section, selectField, SelectOption, textArea, textInput} from "../../../../utils/forms";
import {i18n} from "i18next";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
@Component({
tag: 'elsa-activity-editor-modal',
shadow: false,
})
export class ElsaActivityEditorModal {
@Prop() culture: string;
@State() workflowStorageDescriptors: Array<WorkflowStorageDescriptor> = [];
@State() activityModel: ActivityModel;
@State() activityDescriptor: ActivityDescriptor;
@State() selectedTab: string = 'Properties';
i18next: i18n;
dialog: HTMLElsaModalDialogElement;
form: HTMLFormElement;
formContext: FormContext;
@ -24,18 +28,26 @@ export class ElsaActivityEditorModal {
// This prevents the issue where the designer has e.g. one activity where the user edits the properties, cancels out, then opens the editor again, seeing the entered value still there.
timestamp: Date = new Date();
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
}
componentDidLoad() {
const t = this.t;
eventBus.on(EventTypes.ShowActivityEditor, async (activity: ActivityModel, animate: boolean) => {
this.activityModel = JSON.parse(JSON.stringify(activity));
this.activityDescriptor = state.activityDescriptors.find(x => x.type == activity.type);
this.workflowStorageDescriptors = state.workflowStorageDescriptors;
this.formContext = new FormContext(this.activityModel, newValue => this.activityModel = newValue);
this.selectedTab = 'Properties';
this.selectedTab = t('Properties');
this.timestamp = new Date();
await this.dialog.show(animate);
});
}
t = (key: string) => this.i18next.t(key);
updateActivity(formData: FormData) {
const activity = this.activityModel;
const activityDescriptor = this.activityDescriptor;
@ -67,15 +79,16 @@ export class ElsaActivityEditorModal {
const activityDescriptor: ActivityDescriptor = this.activityDescriptor || {displayName: '', type: '', outcomes: [], category: '', traits: 0, browsable: false, inputProperties: [], outputProperties: [], description: ''};
const propertyCategories = activityDescriptor.inputProperties.filter(x => x.category).map(x => x.category).distinct();
const defaultProperties = activityDescriptor.inputProperties.filter(x => !x.category || x.category.length == 0);
const t = this.t;
let tabs: Array<string> = [];
if (defaultProperties.length > 0) {
tabs.push('Properties');
tabs.push(t('Tabs.Properties.Name'));
}
tabs = [...tabs, ...propertyCategories];
tabs.push('Common');
tabs.push('Storage');
tabs.push(t('Tabs.Common.Name'));
tabs.push(t('Tabs.Storage.Name'));
let selectedTab = this.selectedTab;
@ -103,6 +116,7 @@ export class ElsaActivityEditorModal {
const activityModel: ActivityModel = renderProps.activityModel;
const inactiveClass = 'elsa-border-transparent elsa-text-gray-500 hover:elsa-text-gray-700 hover:elsa-border-gray-300';
const selectedClass = 'elsa-border-blue-500 elsa-text-blue-600';
const t = this.t;
return (
@ -143,12 +157,12 @@ export class ElsaActivityEditorModal {
<div class="elsa-bg-gray-50 elsa-px-4 elsa-py-3 sm:elsa-px-6 sm:elsa-flex sm:elsa-flex-row-reverse">
<button type="submit"
class="elsa-ml-3 elsa-inline-flex elsa-justify-center elsa-py-2 elsa-px-4 elsa-border elsa-border-transparent elsa-shadow-sm elsa-text-sm elsa-font-medium elsa-rounded-md elsa-text-white elsa-bg-blue-600 hover:elsa-bg-blue-700 focus:elsa-outline-none focus:elsa-ring-2 focus:elsa-ring-offset-2 focus:elsa-ring-blue-500">
Save
{t('Buttons.Save')}
</button>
<button type="button"
onClick={() => this.onCancelClick()}
class="elsa-w-full elsa-inline-flex elsa-justify-center elsa-rounded-md elsa-border elsa-border-gray-300 elsa-shadow-sm elsa-px-4 elsa-py-2 elsa-bg-white elsa-text-base elsa-font-medium elsa-text-gray-700 hover:elsa-bg-gray-50 focus:elsa-outline-none focus:elsa-ring-2 focus:elsa-ring-offset-2 focus:elsa-ring-blue-500 sm:elsa-mt-0 sm:elsa-ml-3 sm:elsa-w-auto sm:elsa-text-sm">
Cancel
{t('Buttons.Cancel')}
</button>
</div>
</div>
@ -172,6 +186,7 @@ export class ElsaActivityEditorModal {
renderStorageTab(activityModel: ActivityModel, activityDescriptor: ActivityDescriptor) {
const formContext = this.formContext;
const t = this.t;
let storageDescriptorOptions: Array<SelectOption> = this.workflowStorageDescriptors.map(x => ({value: x.name, text: x.displayName}));
let outputProperties = activityDescriptor.outputProperties;
let inputProperties = activityDescriptor.inputProperties;
@ -185,7 +200,7 @@ export class ElsaActivityEditorModal {
}
return (
<div class={`flex ${this.getHiddenClass('Storage')}`}>
<div class={`flex ${this.getHiddenClass(t('Tabs.Storage.Name'))}`}>
<div class="elsa-space-y-8 elsa-w-full">
{section('Workflow Context')}
@ -209,13 +224,14 @@ export class ElsaActivityEditorModal {
renderCommonTab(activityModel: ActivityModel) {
const formContext = this.formContext;
const t = this.t;
return (
<div class={`flex ${this.getHiddenClass('Common')}`}>
<div class={`flex ${this.getHiddenClass(t('Tabs.Common.Name'))}`}>
<div class="elsa-space-y-8 elsa-w-full">
{textInput(formContext, 'name', 'Name', activityModel.name, 'The technical name of the activity.', 'activityName')}
{textInput(formContext, 'displayName', 'Display Name', activityModel.displayName, 'A friendly name of the activity.', 'activityDisplayName')}
{textArea(formContext, 'description', 'Description', activityModel.description, 'A custom description for this activity', 'activityDescription')}
{textInput(formContext, 'name', t('Tabs.Common.Fields.Name.Label'), activityModel.name, t('Tabs.Common.Fields.Name.Hint'), 'activityName')}
{textInput(formContext, 'displayName', t('Tabs.Common.Fields.DisplayName.Label'), activityModel.displayName, t('Tabs.Common.Fields.DisplayName.Hint'), 'activityDisplayName')}
{textArea(formContext, 'description', t('Tabs.Common.Fields.Description.Label'), activityModel.description, t('Tabs.Common.Fields.Description.Hint'), 'activityDescription')}
</div>
</div>
);
@ -228,9 +244,10 @@ export class ElsaActivityEditorModal {
return undefined;
const key = `activity-settings:${activityModel.activityId}`;
const t = this.t;
return (
<div key={key} class={`elsa-grid elsa-grid-cols-1 elsa-gap-y-6 elsa-gap-x-4 sm:elsa-grid-cols-6 ${this.getHiddenClass('Properties')}`}>
<div key={key} class={`elsa-grid elsa-grid-cols-1 elsa-gap-y-6 elsa-gap-x-4 sm:elsa-grid-cols-6 ${this.getHiddenClass(t('Tabs.Properties.Name'))}`}>
{propertyDescriptors.map(property => this.renderPropertyEditor(activityModel, property))}
</div>
);

View file

@ -0,0 +1,68 @@
export const resources = {
'en': {
'default': {
"Buttons": {
'Save': 'Save',
'Cancel': 'Cancel'
},
'Tabs': {
'Properties': {
'Name': 'Properties'
},
'Common': {
'Name': 'Common',
'Fields': {
'Name': {
'Label': 'Name',
'Hint': 'The technical name of the activity.'
},
'DisplayName': {
'Label': 'Display Name',
'Hint': 'The friendly name of the activity.'
},
'Description': {
'Label': 'Description',
'Hint': 'A custom description for this activity.'
}
}
},
'Storage': {
'Name': 'Storage'
}
}
}
},
'nl-NL': {
'default': {
'Buttons': {
'Save': 'Opslaan',
'Cancel': 'Annuleren'
},
'Tabs': {
'Properties': {
'Name': 'Eigenschappen'
},
'Common': {
'Name': 'Algemeen',
'Fields': {
'Name': {
'Label': 'Naam',
'Hint': 'De technische naam van de activity.'
},
'DisplayName': {
'Label': 'Weergave Naam',
'Hint': 'De gebruikersvriendelijke naam van de activity.'
},
'Description': {
'Label': 'Omschrijving',
'Hint': 'Een aangepaste omschrijving van de activity.'
}
}
},
'Storage': {
'Name': 'Opslag'
}
}
}
}
};

View file

@ -8,6 +8,9 @@ import Tunnel, {WorkflowEditorState} from '../../../../data/workflow-editor';
import {downloadFromBlob} from "../../../../utils/download";
import {ActivityContextMenuState, WorkflowDesignerMode} from "../../../designers/tree/elsa-designer-tree/models";
import {registerClickOutside} from "stencil-click-outside";
import {i18n} from "i18next";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
@Component({
tag: 'elsa-workflow-definition-editor-screen',
@ -23,6 +26,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
@Prop({attribute: 'workflow-definition-id', reflect: true}) workflowDefinitionId: string;
@Prop({attribute: 'server-url', reflect: true}) serverUrl: string;
@Prop({attribute: 'monaco-lib-path', reflect: true}) monacoLibPath: string;
@Prop() culture: string;
@State() workflowDefinition: WorkflowDefinition;
@State() workflowModel: WorkflowModel;
@State() publishing: boolean;
@ -41,6 +45,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
activity: null,
};
i18next: i18n;
el: HTMLElement;
designer: HTMLElsaDesignerTreeElement;
@ -127,11 +132,20 @@ export class ElsaWorkflowDefinitionEditorScreen {
}
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
await this.serverUrlChangedHandler(this.serverUrl);
await this.workflowDefinitionIdChangedHandler(this.workflowDefinitionId);
await this.monacoLibPathChangedHandler(this.monacoLibPath);
}
async componentDidLoad() {
if (!this.designer) {
this.designer = this.el.querySelector("elsa-designer-tree") as HTMLElsaDesignerTreeElement;
this.designer.model = this.workflowModel;
}
}
connectedCallback() {
eventBus.on(EventTypes.UpdateWorkflowSettings, this.onUpdateWorkflowSettings);
}
@ -139,13 +153,8 @@ export class ElsaWorkflowDefinitionEditorScreen {
disconnectedCallback() {
eventBus.detach(EventTypes.UpdateWorkflowSettings, this.onUpdateWorkflowSettings);
}
componentDidLoad() {
if (!this.designer) {
this.designer = this.el.querySelector("elsa-designer-tree") as HTMLElsaDesignerTreeElement;
this.designer.model = this.workflowModel;
}
}
t = (key: string) => this.i18next.t(key);
async loadActivityDescriptors() {
const client = createElsaClient(this.serverUrl);
@ -402,6 +411,8 @@ export class ElsaWorkflowDefinitionEditorScreen {
}
renderActivityContextMenu() {
const t = this.t;
return <div
data-transition-enter="elsa-transition elsa-ease-out elsa-duration-100"
data-transition-enter-start="elsa-transform elsa-opacity-0 elsa-scale-95"
@ -424,7 +435,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
href="#"
class="elsa-block elsa-px-4 elsa-py-2 elsa-text-sm elsa-leading-5 elsa-text-gray-700 hover:elsa-bg-gray-100 hover:elsa-text-gray-900 focus:elsa-outline-none focus:elsa-bg-gray-100 focus:elsa-text-gray-900"
role="menuitem">
Edit
{t('ActivityContextMenu.Edit')}
</a>
</div>
<div class="elsa-border-t elsa-border-gray-100"/>
@ -434,7 +445,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
href="#"
class="elsa-block elsa-px-4 elsa-py-2 elsa-text-sm elsa-leading-5 elsa-text-gray-700 hover:elsa-bg-gray-100 hover:elsa-text-gray-900 focus:elsa-outline-none focus:elsa-bg-gray-100 focus:elsa-text-gray-900"
role="menuitem">
Delete
{t('ActivityContextMenu.Delete')}
</a>
</div>
</div>
@ -446,7 +457,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
}
renderActivityEditor() {
return <elsa-activity-editor-modal/>;
return <elsa-activity-editor-modal culture={this.culture}/>;
}
renderWorkflowSettingsButton() {
@ -471,8 +482,9 @@ export class ElsaWorkflowDefinitionEditorScreen {
if (this.publishing)
return undefined;
const t = this.t;
const message =
this.unPublishing ? 'Unpublishing...' : this.unPublished ? 'Unpublished'
this.unPublishing ? t('Unpublishing...') : this.unPublished ? t('Unpublished')
: this.saving ? 'Saving...' : this.saved ? 'Saved'
: this.importing ? 'Importing...' : this.imported ? 'Imported'
: null;
@ -505,6 +517,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
onUnPublishClicked={() => this.onUnPublishClicked()}
onExportClicked={() => this.onExportClicked()}
onImportClicked={e => this.onImportClicked(e.detail)}
culture={this.culture}
/>;
}

View file

@ -0,0 +1,22 @@
export const resources = {
'en': {
'default': {
'Publishing': 'Publishing...',
'Published': 'Published',
"ActivityContextMenu":{
"Edit": "Edit",
"Delete": "Delete"
}
}
},
'nl-NL': {
'default': {
'Publishing': 'Publiceren...',
'Published': 'Gepubliceerd',
"ActivityContextMenu":{
"Edit": "Bewerken",
"Delete": "Verwijderen"
}
}
}
};

View file

@ -1,9 +1,11 @@
import {Component, Host, h, Prop, State, Event, EventEmitter, Watch} from '@stencil/core';
import {enter, leave, toggle} from 'el-transition'
import {leave, toggle} from 'el-transition'
import {registerClickOutside} from "stencil-click-outside";
import {VersionOptions, WorkflowDefinition} from "../../../../models";
import {createElsaClient} from "../../../../services/elsa-client";
import {WorkflowDefinition} from "../../../../models";
import Tunnel from '../../../../data/workflow-editor';
import {i18n} from "i18next";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
@Component({
tag: 'elsa-workflow-publish-button',
@ -13,13 +15,21 @@ export class ElsaWorkflowPublishButton {
@Prop() workflowDefinition: WorkflowDefinition;
@Prop() publishing: boolean;
@Prop() culture: string;
@Event({bubbles: true}) publishClicked: EventEmitter;
@Event({bubbles: true}) unPublishClicked: EventEmitter;
@Event({bubbles: true}) exportClicked: EventEmitter;
@Event({bubbles: true}) importClicked: EventEmitter<File>;
i18next: i18n;
menu: HTMLElement;
fileInput: HTMLInputElement;
async componentWillLoad(){
this.i18next = await loadTranslations(this.culture, resources);
}
t = (key: string) => this.i18next.t(key);
closeMenu() {
leave(this.menu);
@ -66,6 +76,8 @@ export class ElsaWorkflowPublishButton {
}
render() {
const t = this.t;
return (
<Host class="elsa-block" ref={el => registerClickOutside(this, el, this.closeMenu)}>
<span class="elsa-relative elsa-z-0 elsa-inline-flex elsa-shadow-sm elsa-rounded-md">
@ -90,11 +102,11 @@ export class ElsaWorkflowPublishButton {
<div class="elsa-py-1" role="none">
<a href="#" onClick={e => this.onExportClick(e)} class="elsa-block elsa-px-4 elsa-py-2 elsa-text-sm elsa-text-gray-700 hover:elsa-bg-gray-100 hover:elsa-text-gray-900" role="menuitem">
Export
{t('Export')}
</a>
<a href="#" onClick={e => this.onImportClick(e)} class="elsa-block elsa-px-4 elsa-py-2 elsa-text-sm elsa-text-gray-700 hover:elsa-bg-gray-100 hover:elsa-text-gray-900" role="menuitem">
Import
{t('Import')}
</a>
</div>
@ -110,16 +122,20 @@ export class ElsaWorkflowPublishButton {
}
renderPublishButton() {
const t = this.t;
return (
<button type="button"
onClick={() => this.onPublishClick()}
class="elsa-relative elsa-inline-flex elsa-items-center elsa-px-4 elsa-py-2 elsa-rounded-l-md elsa-border elsa-border-gray-300 elsa-bg-white elsa-text-sm elsa-font-medium elsa-text-gray-700 hover:elsa-bg-gray-50 focus:elsa-z-10 focus:elsa-outline-none focus:elsa-ring-1 focus:elsa-ring-blue-500 focus:elsa-border-blue-500">
Publish
{t('Publish')}
</button>);
}
renderPublishingButton() {
const t = this.t;
return (
<button type="button"
disabled={true}
@ -129,7 +145,7 @@ export class ElsaWorkflowPublishButton {
<circle class="elsa-opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
<path class="elsa-opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
</svg>
Publishing
{t('Publishing')}
</button>);
}
@ -137,10 +153,12 @@ export class ElsaWorkflowPublishButton {
if (!this.workflowDefinition.isPublished)
return undefined;
const t = this.t;
return (
<div class="elsa-py-1" role="none">
<a href="#" onClick={e => this.onUnPublishClick(e)} class="elsa-block elsa-px-4 elsa-py-2 elsa-text-sm elsa-text-gray-700 hover:elsa-bg-gray-100 hover:elsa-text-gray-900" role="menuitem">
Unpublish
{t('Unpublish')}
</a>
</div>
);

View file

@ -0,0 +1,20 @@
export const resources = {
'en': {
'default': {
'Publish': 'Publish',
'Publishing': 'Publishing',
'Unpublish': 'Unpublish',
'Import': 'Import',
'Export': 'Export',
}
},
'nl-NL': {
'default': {
'Publish': 'Publiceren',
'Publishing': 'Bezig met publiceren',
'Unpublish': 'Niet-publiceren',
'Import': 'Importeren',
'Export': 'Exporteren',
}
}
};

View file

@ -2,6 +2,10 @@ import {Component, h, Prop, State} from '@stencil/core';
import {createElsaClient} from "../../../../services/elsa-client";
import {PagedList, VersionOptions, WorkflowDefinitionSummary} from "../../../../models";
import {RouterHistory} from "@stencil/router";
import {i18n} from "i18next";
import {loadTranslations} from "../../../i18n/i18n-loader";
import {resources} from "./localizations";
import {GetIntlMessage} from "../../../i18n/intl-message";
@Component({
tag: 'elsa-workflow-definitions-list-screen',
@ -10,17 +14,21 @@ import {RouterHistory} from "@stencil/router";
export class ElsaWorkflowDefinitionsListScreen {
@Prop() history?: RouterHistory;
@Prop() serverUrl: string;
@Prop() culture: string;
@State() workflowDefinitions: PagedList<WorkflowDefinitionSummary> = {items: [], page: 1, pageSize: 50, totalCount: 0};
@State() publishedWorkflowDefinitions: WorkflowDefinitionSummary[] = [];
private i18next: i18n;
confirmDialog: HTMLElsaConfirmDialogElement;
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
await this.loadWorkflowDefinitions();
}
async onDeleteClick(e: Event, workflowDefinition: WorkflowDefinitionSummary) {
const result = await this.confirmDialog.show('Delete Workflow Definition', 'Are you sure you wish to permanently delete this workflow, including all of its workflow instances?');
const t = x => this.i18next.t(x);
const result = await this.confirmDialog.show(t('DeleteConfirmationModel.Title'), t('DeleteConfirmationModel.Message'));
if (!result)
return;
@ -48,6 +56,8 @@ export class ElsaWorkflowDefinitionsListScreen {
render() {
const workflowDefinitions = this.workflowDefinitions.items;
const i18next = this.i18next;
const IntlMessage = GetIntlMessage(i18next);
return (
<div>
@ -55,15 +65,17 @@ export class ElsaWorkflowDefinitionsListScreen {
<table class="elsa-min-w-full">
<thead>
<tr class="elsa-border-t elsa-border-gray-200">
<th class="elsa-px-6 elsa-py-3 elsa-border-b elsa-border-gray-200 elsa-bg-gray-50 elsa-text-left elsa-text-xs elsa-leading-4 elsa-font-medium elsa-text-gray-500 elsa-uppercase elsa-tracking-wider"><span class="lg:elsa-pl-2">Name</span></th>
<th class="elsa-px-6 elsa-py-3 elsa-border-b elsa-border-gray-200 elsa-bg-gray-50 elsa-text-left elsa-text-xs elsa-leading-4 elsa-font-medium elsa-text-gray-500 elsa-uppercase elsa-tracking-wider">
Instances
<span class="lg:elsa-pl-2"><IntlMessage label="Name"/></span>
</th>
<th class="elsa-px-6 elsa-py-3 elsa-border-b elsa-border-gray-200 elsa-bg-gray-50 elsa-text-left elsa-text-xs elsa-leading-4 elsa-font-medium elsa-text-gray-500 elsa-uppercase elsa-tracking-wider">
<IntlMessage label="Instances"/>
</th>
<th class="hidden md:elsa-table-cell elsa-px-6 elsa-py-3 elsa-border-b elsa-border-gray-200 elsa-bg-gray-50 elsa-text-right elsa-text-xs elsa-leading-4 elsa-font-medium elsa-text-gray-500 elsa-uppercase elsa-tracking-wider">
Latest Version
<IntlMessage label="LatestVersion"/>
</th>
<th class="hidden md:elsa-table-cell elsa-px-6 elsa-py-3 elsa-border-b elsa-border-gray-200 elsa-bg-gray-50 elsa-text-right elsa-text-xs elsa-leading-4 elsa-font-medium elsa-text-gray-500 elsa-uppercase elsa-tracking-wider">
Published Version
<IntlMessage label="PublishedVersion"/>
</th>
<th class="elsa-pr-6 elsa-py-3 elsa-border-b elsa-border-gray-200 elsa-bg-gray-50 elsa-text-right elsa-text-xs elsa-leading-4 elsa-font-medium elsa-text-gray-500 elsa-uppercase elsa-tracking-wider"/>
</tr>
@ -112,7 +124,7 @@ export class ElsaWorkflowDefinitionsListScreen {
<td class="elsa-px-6 elsa-py-3 elsa-text-sm elsa-leading-5 elsa-text-gray-500 elsa-font-medium">
<div class="elsa-flex elsa-items-center elsa-space-x-3 lg:elsa-pl-2">
<stencil-route-link url={instancesUrl} anchorClass="elsa-truncate hover:elsa-text-gray-600">Instances</stencil-route-link>
<stencil-route-link url={instancesUrl} anchorClass="elsa-truncate hover:elsa-text-gray-600"><IntlMessage label="Instances"/></stencil-route-link>
</div>
</td>
@ -120,8 +132,8 @@ export class ElsaWorkflowDefinitionsListScreen {
<td class="hidden md:elsa-table-cell elsa-px-6 elsa-py-3 elsa-whitespace-no-wrap elsa-text-sm elsa-leading-5 elsa-text-gray-500 elsa-text-right">{publishedVersionNumber}</td>
<td class="elsa-pr-6">
<elsa-context-menu history={this.history} menuItems={[
{text: 'Edit', anchorUrl: editUrl, icon: editIcon},
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowDefinition), icon: deleteIcon}
{text: i18next.t('Edit'), anchorUrl: editUrl, icon: editIcon},
{text: i18next.t('Delete'), clickHandler: e => this.onDeleteClick(e, workflowDefinition), icon: deleteIcon}
]}/>
</td>
</tr>
@ -131,7 +143,7 @@ export class ElsaWorkflowDefinitionsListScreen {
</table>
</div>
<elsa-confirm-dialog ref={el => this.confirmDialog = el}/>
<elsa-confirm-dialog ref={el => this.confirmDialog = el} culture={this.culture}/>
</div>
);
}

View file

@ -0,0 +1,30 @@
export const resources = {
'en': {
'default': {
'Name': 'Name',
'Instances': 'Instances',
'LatestVersion': 'Latest Version',
'PublishedVersion': 'Published Version',
'Edit': 'Edit',
'Delete': 'Delete',
'DeleteConfirmationModel': {
'Title': 'Delete Workflow Definition',
'Message': 'Are you sure you wish to permanently delete this workflow, including all of its workflow instances?'
}
}
},
'nl-NL': {
'default': {
'Name': 'Naam',
'Instances': 'Instanties',
'LatestVersion': 'Laatste Versie',
'PublishedVersion': 'Gepubliceerde Versie',
'Edit': 'Bewerken',
'Delete': 'Verwijderen',
'DeleteConfirmationModel': {
'Title': 'Verwijder Workflow Definitie',
'Message': 'Weet je zeker dat je deze workflow permanent wilt verwijderen, inclusief alle bijbehorende workflow instanties?'
}
}
}
};

View file

@ -1,4 +1,7 @@
import {Component, h, Host, Method, State} from '@stencil/core';
import {Component, h, Host, Method, Prop, State} from '@stencil/core';
import {i18n} from "i18next";
import {loadTranslations} from "../../i18n/i18n-loader";
import {resources} from "./localizations";
@Component({
tag: 'elsa-confirm-dialog',
@ -8,6 +11,8 @@ export class ElsaConfirmDialog {
@State() caption: string;
@State() message: string;
@Prop() culture: string;
private i18next: i18n;
dialog: HTMLElsaModalDialogElement;
fulFill: (value: (PromiseLike<boolean> | boolean)) => void;
@ -31,6 +36,10 @@ export class ElsaConfirmDialog {
await this.dialog.hide(true);
}
async componentWillLoad() {
this.i18next = await loadTranslations(this.culture, resources);
}
async onDismissClick() {
this.fulFill(false);
await this.hide();
@ -44,6 +53,8 @@ export class ElsaConfirmDialog {
}
render() {
const t = x => this.i18next.t(x);
return (
<Host>
<elsa-modal-dialog ref={el => this.dialog = el}>
@ -81,12 +92,12 @@ export class ElsaConfirmDialog {
<button type="button"
onClick={() => this.onAcceptClick()}
class="elsa-w-full elsa-inline-flex elsa-justify-center elsa-rounded-md elsa-border elsa-border-transparent elsa-shadow-sm elsa-px-4 elsa-py-2 elsa-bg-red-600 elsa-text-base elsa-font-medium elsa-text-white hover:elsa-bg-red-700 focus:elsa-outline-none focus:elsa-ring-2 focus:elsa-ring-offset-2 focus:elsa-ring-red-500 sm:elsa-ml-3 sm:elsa-w-auto sm:elsa-text-sm">
Yes
{t('Yes')}
</button>
<button type="button"
onClick={() => this.onDismissClick()}
class="elsa-mt-3 elsa-w-full elsa-inline-flex elsa-justify-center elsa-rounded-md elsa-border elsa-border-gray-300 elsa-shadow-sm elsa-px-4 elsa-py-2 elsa-bg-white elsa-text-base elsa-font-medium elsa-text-gray-700 hover:elsa-text-gray-500 focus:elsa-outline-none focus:elsa-ring-2 focus:elsa-ring-offset-2 focus:ring-indigo-500 sm:elsa-mt-0 sm:elsa-w-auto sm:elsa-text-sm">
No
{t('No')}
</button>
</div>
</div>

View file

@ -0,0 +1,14 @@
export const resources = {
'en': {
'default': {
'Yes': 'Yes',
'No': 'No'
}
},
'nl-NL': {
'default': {
'Yes': 'Ja',
'No': 'Nee',
}
}
};

View file

@ -14,7 +14,7 @@
</head>
<body>
<elsa-studio-root server-url="https://localhost:11000" monaco-lib-path="build/assets/js/monaco-editor/min"></elsa-studio-root>
<elsa-studio-root server-url="https://localhost:11000" monaco-lib-path="build/assets/js/monaco-editor/min" culture="nl-NL"></elsa-studio-root>
<!--<elsa-workflow-definition-editor-screen server-url="https://localhost:11000" monaco-lib-path="build/assets/js/monaco-editor/min"></elsa-workflow-definition-editor-screen>-->
<!--<elsa-workflow-instance-list-screen server-url="https://localhost:11000"></elsa-workflow-instance-list-screen>-->
<!--<elsa-external-events></elsa-external-events>-->