403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/bizproc/workflow/faces/src/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/bizproc/workflow/faces/src/faces.js
import { Summary } from 'bizproc.workflow.faces.summary';
import { ajax, Dom, Tag, Text, Type } from 'main.core';
import type { FooterType, StackType, StepType } from 'ui.image-stack-steps';
import { footerTypeEnum, headerTypeEnum, ImageStackSteps, imageTypeEnum, stackStatusEnum } from 'ui.image-stack-steps';
import { validateFacesData, workflowFacesDataValidator } from './helpers/validators';

import 'ui.design-tokens';
import 'ui.icons';
import 'ui.icon-set.main';

import type { Avatar, FacesData, StepData, WorkflowFacesData } from './types/workflow-faces';

import './css/style.css';

export type { FacesData, WorkflowFacesData, Avatar };

export class WorkflowFaces
{
	#target: HTMLElement;
	#data: FacesData = {};
	#showArrow: boolean = false;
	#showTimeStep: boolean = false;
	#workflowId: string;
	#targetUserId: number;

	#stack: ImageStackSteps;
	#unsubscribePushCallback = null;
	#node: null;
	#timelineNode: null;
	#errorNode: null;

	constructor(data: WorkflowFacesData)
	{
		if (!workflowFacesDataValidator(data))
		{
			throw new TypeError('Bizproc.Workflow.Faces: data must be correct plain object');
		}

		this.#workflowId = data.workflowId;
		this.#target = data.target;
		this.#targetUserId = data.targetUserId || 0;
		this.#data = data.data;

		if (Type.isBoolean(data.showArrow))
		{
			this.#showArrow = data.showArrow;
		}

		if (Type.isBoolean(data.showTimeStep))
		{
			this.#showTimeStep = data.showTimeStep;
		}

		this.#initStack();
		if (data.subscribeToPushes && !data.isWorkflowFinished)
		{
			this.#subscribeToPushes();
		}
	}

	#initStack()
	{
		this.#stack = new ImageStackSteps({ steps: this.#getStackSteps() });
	}

	#getStackSteps(): []
	{
		const steps = [];
		this.#data.steps.forEach((stepData) => {
			steps.push(this.#createStep(stepData));
		});

		if (steps.length < 3)
		{
			for (let i = steps.length; i < 3; i++)
			{
				steps.push(this.#getStubStep());
			}
		}

		if (this.#data.progressBox && this.#data.progressBox.progressTasksCount > 0)
		{
			steps[0].progressBox = { title: this.#data.progressBox.text };
		}

		return steps.map((step, index) => ({ ...step, id: `step-${index}` }));
	}

	#createStep(data: StepData): StepType
	{
		return {
			id: data.id,
			header: { type: headerTypeEnum.TEXT, data: { text: data.name } },
			stack: this.#getStack(data),
			footer: this.#getFooter(data),
			styles: { minWidth: 75 },
		};
	}

	#getStack(data: StepData): StackType
	{
		const userStack = this.#getUserStack(data);
		if (userStack)
		{
			return userStack;
		}

		return this.#getIconStack(data);
	}

	#getUserStack(data: StepData): ?StackType
	{
		const images = this.#getStackUserImages(data.avatarsData);
		if (Type.isArrayFilled(images))
		{
			const stack = { images };

			let status = null;
			switch (data.status)
			{
				case 'wait':
					status = stackStatusEnum.WAIT;
					break;
				case 'success':
					status = stackStatusEnum.OK;
					break;
				case 'not-success':
					status = stackStatusEnum.CANCEL;
					break;
				default:
					status = null;
			}

			if (status)
			{
				stack.status = { type: status };
			}

			return stack;
		}

		return null;
	}

	#getStackUserImages(avatars): []
	{
		const images = [];
		if (Type.isArrayFilled(avatars))
		{
			avatars.forEach((avatar) => {
				const userId = Text.toInteger(avatar.id);
				if (userId > 0)
				{
					images.push({
						type: imageTypeEnum.USER,
						data: { userId, src: String(avatar.avatarUrl || '') },
					});
				}
			});
		}

		return images;
	}

	#getIconStack(data: StepData): StackType
	{
		let icon = null;
		let color = null;
		switch (data.id)
		{
			case 'completed':
				icon = data.success ? 'circle-check' : 'cross-circle-60';
				color = data.success ? 'var(--ui-color-primary-alt)' : 'var(--ui-color-base-35)';
				break;
			case 'running':
				icon = 'black-clock';
				color = 'var(--ui-color-palette-blue-60)';
				break;
			case 'done':
				icon = 'circle-check';
				color = 'var(--ui-color-primary-alt)';
				break;
			default:
				icon = 'bp';
				color = 'var(--ui-color-palette-gray-20)';
		}

		return { images: [{ type: imageTypeEnum.ICON, data: { icon, color } }] };
	}

	#getFooter(data: StepData): FooterType
	{
		if (
			(Type.isNumber(data.duration) && data.duration > 0)
			|| (data.id === 'running')
		)
		{
			return {
				type: footerTypeEnum.DURATION,
				data: { duration: Text.toInteger(data.duration), realtime: data.id === 'running' },
			};
		}

		return {
			type: footerTypeEnum.TEXT,
			data: { text: String(data.duration) },
		};
	}

	#getStubStep(): StepType
	{
		return {
			id: 'stub',
			header: { type: headerTypeEnum.STUB },
			stack: { images: [{ type: imageTypeEnum.USER_STUB }] },
			footer: { type: footerTypeEnum.STUB },
			styles: { minWidth: 75 },
		};
	}

	#subscribeToPushes()
	{
		if (BX.PULL)
		{
			this.#unsubscribePushCallback = BX.PULL.subscribe({
				moduleId: 'bizproc',
				command: 'workflow',
				callback: this.#onWorkflowPush.bind(this),
			});
		}
	}

	#onWorkflowPush(params)
	{
		if (params && params.eventName === 'UPDATED' && Type.isArrayFilled(params.items))
		{
			for (const item of params.items)
			{
				if (String(item.id) === this.#workflowId)
				{
					this.#loadWorkflowFaces();

					return;
				}
			}
		}
	}

	#loadWorkflowFaces()
	{
		if (this.#target && Type.isDomNode(this.#target) && this.#target.clientHeight > 0)
		{
			ajax.runAction('bizproc.workflow.faces.load', {
				data: {
					workflowId: this.#workflowId,
					runningTaskId: this.#getRunningTaskId(),
					userId: this.#targetUserId,
				},
			}).then(({ data }) => {
				if (Type.isDomNode(this.#errorNode))
				{
					Dom.replace(this.#errorNode, this.#node);
					this.#errorNode = null;
				}

				this.updateData(data);
			}).catch(({ errors }) => {
				if (Type.isArrayFilled(errors))
				{
					const firstError = errors.pop();
					if (firstError.code === 'ACCESS_DENIED')
					{
						Dom.replace(
							this.#node,
							this.#renderError(firstError.message),
						);

						this.errorMessage = firstError.message;
					}
				}
			});
		}
	}

	#getRunningTaskId(): number
	{
		const runningStep = this.#data.steps.find((step) => step.id === 'running');
		if (runningStep)
		{
			return runningStep.taskId;
		}

		return 0;
	}

	#unsubscribeToPushes()
	{
		if (Type.isFunction(this.#unsubscribePushCallback))
		{
			this.#unsubscribePushCallback();
			this.#unsubscribePushCallback = null;
		}
	}

	render()
	{
		if (this.#node)
		{
			return;
		}

		this.#node = Tag.render`<div class="bp-workflow-faces"></div>`;
		Dom.append(this.#node, this.#target);
		this.#stack.renderTo(this.#node);

		if (this.#showArrow)
		{
			Dom.append(Tag.render`<div class="bp-workflow-faces-arrow"></div>`, this.#node);
		}

		if (this.#showTimeStep && this.#data.timeStep)
		{
			Dom.append(this.#renderTimeline(), this.#node);
		}
	}

	updateData(data)
	{
		const facesData = {
			steps: data.steps,
			progressBox: data.progressBox,
			timeStep: data.timeStep,
		};

		if (!validateFacesData(facesData))
		{
			return;
		}

		this.#data = facesData;

		this.#getStackSteps().forEach((step) => {
			this.#stack.updateStep(step, step.id);
		});

		if (data.isWorkflowFinished)
		{
			this.#unsubscribeToPushes();
			if (this.#showTimeStep)
			{
				Dom.replace(this.#timelineNode, this.#renderTimeline());
			}
		}
	}

	#renderTimeline(): HTMLElement
	{
		const timeline = new Summary({
			workflowId: this.#workflowId,
			data: this.#data.timeStep,
		});
		this.#timelineNode = timeline.render();

		return this.#timelineNode;
	}

	#renderError(message: string): HTMLElement
	{
		this.#errorNode = Tag.render`
			<div class="bp-workflow-faces">
				<span class="bp-workflow-faces-error-message">
					${Text.encode(message)}
				</span>
			</div>
		`;

		return this.#errorNode;
	}

	destroy()
	{
		this.#unsubscribeToPushes();

		this.#stack.destroy();
		this.#stack = null;

		this.#target = null;
		this.#data = null;
		this.#workflowId = null;

		Dom.clean(this.#timelineNode);
		this.#timelineNode = null;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit