@bernierllc/generic-workflow-ui
Version:
Generic, reusable workflow UI components with linear and graph visualization
83 lines (82 loc) • 4.79 kB
JavaScript
"use strict";
/*
Copyright (c) 2025 Bernier LLC
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenericWorkflowTimeline = GenericWorkflowTimeline;
const react_1 = __importStar(require("react"));
const tamagui_1 = require("tamagui");
const date_fns_1 = require("date-fns");
const defaultConfig = {
enabled: true,
orientation: 'vertical',
showTimestamps: true,
showUsers: true,
showDescriptions: true,
showIcons: true,
maxItems: undefined,
showToggle: true
};
function GenericWorkflowTimeline({ items, config: userConfig = {}, onItemClick, disabled = false, customItemRenderer }) {
const config = { ...defaultConfig, ...userConfig };
const [expanded, setExpanded] = (0, react_1.useState)(false);
if (!config.enabled) {
return react_1.default.createElement(react_1.default.Fragment, null);
}
const sortedItems = [...items].sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
const displayItems = config.maxItems && !expanded
? sortedItems.slice(0, config.maxItems)
: sortedItems;
const hasMore = config.maxItems && sortedItems.length > config.maxItems;
const renderItem = (item, index) => {
if (customItemRenderer) {
return customItemRenderer(item);
}
return (react_1.default.createElement(tamagui_1.XStack, { key: item.id, gap: "$3", alignItems: "flex-start", cursor: onItemClick && !disabled ? 'pointer' : 'default', opacity: disabled ? 0.5 : 1, onPress: () => onItemClick && !disabled && onItemClick(item) },
config.showIcons && (react_1.default.createElement(tamagui_1.Circle, { size: "$3", backgroundColor: item.color || '$blue10', justifyContent: "center", alignItems: "center" }, item.icon || (react_1.default.createElement(tamagui_1.Text, { color: "white", fontSize: "$2" }, index + 1)))),
react_1.default.createElement(tamagui_1.YStack, { flex: 1, gap: "$1" },
react_1.default.createElement(tamagui_1.XStack, { justifyContent: "space-between", alignItems: "center" },
react_1.default.createElement(tamagui_1.Text, { fontWeight: "bold", fontSize: "$4" }, item.stageName),
config.showTimestamps && (react_1.default.createElement(tamagui_1.Text, { fontSize: "$2", color: "$gray10" }, (0, date_fns_1.format)(item.timestamp, 'MMM d, yyyy h:mm a')))),
config.showUsers && item.userName && (react_1.default.createElement(tamagui_1.Text, { fontSize: "$3", color: "$gray11" }, item.userName)),
config.showDescriptions && item.description && (react_1.default.createElement(tamagui_1.Text, { fontSize: "$3", color: "$gray10" }, item.description)))));
};
return (react_1.default.createElement(tamagui_1.Card, { padding: "$4", elevate: true },
react_1.default.createElement(tamagui_1.YStack, { gap: "$3" },
react_1.default.createElement(tamagui_1.Text, { fontSize: "$5", fontWeight: "bold" }, "Timeline"),
react_1.default.createElement(tamagui_1.YStack, { gap: "$3" }, displayItems.map((item, index) => renderItem(item, index))),
hasMore && config.showToggle && (react_1.default.createElement(tamagui_1.Text, { fontSize: "$3", color: "$blue10", cursor: "pointer", onPress: () => setExpanded(!expanded), textAlign: "center" }, expanded ? 'Show Less' : `Show ${sortedItems.length - displayItems.length} More`)))));
}