Skip to content

Commit

Permalink
2.4.1 workflow 搜索 用户环境变量添加
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaobaidadada committed Feb 3, 2025
1 parent 771d650 commit bd4e5f1
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 36 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "filecat",
"version": "2.3.3",
"version": "2.4.1",
"description": "filecat 文件管理器",
"author": "xiaobaidadada",
"scripts": {
Expand Down
14 changes: 14 additions & 0 deletions src/common/ValueUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,17 @@ export function formatFileSize(bytes) {
}
}

// 格式化时间 2025/02/04 03:37:07
export function formatter_time(date){
const formatter = new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false // 使用24小时制
});
return formatter.format(date);
}

3 changes: 2 additions & 1 deletion src/common/frame/WsData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ export enum CmdType {
workflow_get,
workflow_realtime,
workflow_realtime_one_req,
workflow_realtime_one_rsq
workflow_realtime_one_rsq,
workflow_search_by_run_name,

}

Expand Down
2 changes: 2 additions & 0 deletions src/common/req/file.req.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ export class WorkflowGetReq {

index:number; // 数据的索引 如果存在忽略 page参数

search_name:string;

}
export type work_flow_record = base_data_record<
{
Expand Down
18 changes: 12 additions & 6 deletions src/main/domain/data/basedata/base_data_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,31 +77,37 @@ export class Base_data_util {
* @returns {null}
*/
find_one(judge_handle) {
const list = this.find_list(judge_handle);
if(list.size === 0) {
return null;
}
return list[0];
}

// 从头到尾的搜索没有索引 索引功能以后再添加
find_list(judge_handle){
let position = 0;
let buffer = Buffer.alloc(4); // 每个元素 都是 4
let num = 0; // 元素位置从1开始
const list_fd = fs.openSync(path.join(this.base_dir,filecat_meta_list_filename), "r");
const data_fd = fs.openSync(path.join(this.base_dir, filecat_data_filename), 'r');
let r = null;
const r = [];
while (1) {
const bytesRead = fs.readSync(list_fd, buffer,
0, // 相对于当前的偏移位置
buffer.length, // 读取的长度
position // 当前位置 往前推进了一点
);
if(bytesRead < 4) {
return null;
return r;
}
num++;
let start = buffer.readUInt32LE(0);
const meta = this.get_meata(start,data_fd);
if(judge_handle(num,meta)) {
r = {meta: meta, data: this.get_data(start,data_fd)};
break;
r.push({meta: meta, data: this.get_data(start,data_fd)})
}
// return {meta: meta, data: this.get_data(start,data_fd)};
position+=4;
// break
}
fs.closeSync(list_fd);
fs.closeSync(data_fd);
Expand Down
6 changes: 5 additions & 1 deletion src/main/domain/file/file.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ export class FileController {
@msg(CmdType.workflow_exec)
async workflow_exec(data: WsData<WorkflowReq>) {
userService.check_user_auth((data.wss as Wss).token, UserAuth.workflow_exe);
// todo 数据库位置查找失败
await workflowService.workflow_exec(data);
return "";
}
Expand All @@ -257,4 +256,9 @@ export class FileController {
return workflowService.workflow_realtime_one(data);
}

@msg(CmdType.workflow_search_by_run_name)
async workflow_search_by_run_name(data: WsData<WorkFlowRealTimeOneReq>) {
return workflowService.workflow_search_by_run_name(data);
}

}
4 changes: 4 additions & 0 deletions src/main/domain/file/workflow/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ run-name: 构建项目 # 用于日志显示的名字
env: # 定义一些环境变量 这些 环境变量可以在 run 或者 cwd 中 或者 run-name 中使用 {{}} 来表达 使用的时候 必须要用 '' 字符串括起来,不然会被处理成变量 {{{ }}} 是非转义方式 采用 Mustache js
version: 1
cmd_install: npm install
# 有几个参数是每次执行自动添加的
# filecat_user_id: 1 # 用户id
# filecat_user_name: admin # 用户名字
# filecat_user_note: 备注 #用户备注

username: admin # 需要执行用户的账号 该脚本需要运行在某个用户下
user_id: 1 # 会覆盖 username 对应的用户 id 只允许特定设置的用户在这里可以被设置 运行
Expand Down
54 changes: 48 additions & 6 deletions src/main/domain/file/workflow/workflow.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {getSys, sysType} from "../../shell/shell.service";
import {Base_data_util} from "../../data/basedata/base_data_util";
import {removeTrailingPath} from "../../../../common/StringUtil";
import {tree_list, workflow_realtime_tree_list} from "../../../../common/req/common.pojo";
import {formatter_time} from "../../../../common/ValueUtil";

const readYamlFile = require('read-yaml-file')
const pty: any = require("@xiaobaidadada/node-pty-prebuilt")
Expand Down Expand Up @@ -128,14 +129,26 @@ class work_children {
}
}

public async init(param?: { env: any,not_log?:boolean,yaml_data?:any,yaml_path?:string }) {
public async init(param?: {
env?: any,
not_log?:boolean,
yaml_data?:any,
yaml_path?:string,
filecat_user_id?:string,
filecat_user_name?:string,
filecat_user_note?:string
}) {
if(param?.yaml_path) {
this.yaml_path = param.yaml_path;
}
this.filename = path.basename(this.yaml_path);
const yaml_data = param?.yaml_data ?? await readYamlFile(this.yaml_path);
// 环境变量设置
this.env = yaml_data.env;
// 获取用户 id
this.env['filecat_user_id'] = param.filecat_user_id;
this.env['filecat_user_name'] = param.filecat_user_name;
this.env['filecat_user_note'] = param.filecat_user_note;
// 获取用户 id
let user_id = `${yaml_data.user_id??""}`;
if (!user_id) {
user_id = userService.get_user_id(`${yaml_data.username}`);
Expand Down Expand Up @@ -192,8 +205,8 @@ class work_children {
}
}
}
yaml_data['run-name'] = Mustache.render(yaml_data['run-name'], this.env??"");
this["run-name"] = `${yaml_data['run-name']??""}`;
yaml_data['run-name'] = Mustache.render(this["run-name"], this.env??"");
this.name = `${yaml_data.name}`;
if (param?.env) {
for (const key of Object.keys(param.env)) {
Expand Down Expand Up @@ -250,7 +263,7 @@ class work_children {
name:this.name,
"run-name":this["run-name"],
is_success: fail_list.length === 0,
timestamp:new Date().toISOString(),
timestamp:formatter_time(new Date()),
duration:`${((Date.now() - start_time)/1000).toFixed(2)} s` // s 秒
}));
} catch (error) {
Expand Down Expand Up @@ -413,7 +426,14 @@ class work_children {
const yaml = this.import_files_map.get(step["use-yml"]);
if(yaml) {
const worker = new work_children(undefined, this.workflow_dir_path);
await worker.init({env:step['with-env'],yaml_data:yaml.yaml_data,yaml_path:yaml.yaml_path});
await worker.init({
env:step['with-env'],
yaml_data:yaml.yaml_data,
yaml_path:yaml.yaml_path,
filecat_user_name: this.env['filecat_user_name'],
filecat_user_id: this.env['filecat_user_id'],
filecat_user_note: this.env['filecat_user_note'],
});
this.worker_children_use_yml_map.set(step["use-yml"],worker);
let success_list,fail_list;
try {
Expand Down Expand Up @@ -530,13 +550,18 @@ export class WorkflowService {
const pojo = data.context as WorkflowReq;
const root_path = settingService.getFileRootPath(token);
const file_path = path.join(root_path, decodeURIComponent(pojo.path));
const user_info = userService.get_user_info_by_token(token);
if (pojo.run_type === WorkRunType.start) {
if (work_exec_map.get(file_path))
throw "Workflow exec task already exists";
const worker = new work_children(file_path);
work_exec_map.set(file_path, worker);
try {
await worker.init();
await worker.init({
filecat_user_id:user_info.user_id,
filecat_user_name:user_info.username,
filecat_user_note:user_info.note
});
} catch (e){
work_exec_map.delete(file_path);
this.online_change_push();
Expand Down Expand Up @@ -610,6 +635,23 @@ export class WorkflowService {
return r;
}

public async workflow_search_by_run_name(data:WsData<WorkflowGetReq>) {
const token: string = (data.wss as Wss).token;
const pojo = data.context as WorkflowGetReq;
const root_path = settingService.getFileRootPath(token);
const dir_path = path.join(root_path, decodeURIComponent(pojo.dir_path),workflow_dir_name);
const basedata = new Base_data_util({base_dir:dir_path});
const r = new WorkflowGetRsq();
const regex = new RegExp(pojo.search_name);
// @ts-ignore
r.list = basedata.find_list((index,meta)=>{
if(!meta)return false;
return regex.test(JSON.parse(meta)['run-name']);
});
r.total = basedata.find_num();
return r;
}

public workflow_realtime(data: WsData<WorkFlowRealTimeReq>) {
const token: string = (data.wss as Wss).token;
const pojo = data.context as WorkflowGetReq;
Expand Down
6 changes: 3 additions & 3 deletions src/web/meta/component/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function Input(props: {
type?: string,
handleInputChange?: (event: string, target: any) => void,
value?: string,
handlerEnter?:()=>void,
handlerEnter?:(v)=>void,
focus?:boolean,
no_border?:boolean,
left_placeholder?:string,
Expand Down Expand Up @@ -98,7 +98,7 @@ function Input(props: {
onKeyPress={(event) => {
if (event.key === 'Enter') {
if (props.handlerEnter) {
props.handlerEnter();
props.handlerEnter(event.target.value);
}
}
}}
Expand All @@ -124,7 +124,7 @@ export function InputText(props: {
placeholderOut?: string,
handleInputChange?: (value: string) => void,
value?: string,
handlerEnter?: () => void,
handlerEnter?: (v) => void,
no_border?: boolean,
left_placeholder?: string,
right_placeholder?:string
Expand Down
71 changes: 53 additions & 18 deletions src/web/project/component/file/component/workflow/WorkFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export function WorkFlow(props) {
const [page_size,set_page_size] = useState(10);
const [total,set_total] = useState(0);
const [max_page_num,set_max_page_num] = useState(0);
const [search_name,set_search_name] = useState("")
const [search_name_status,set_search_name_status] = useState(false)

const task_headers = [t("序号"),t("运行名称"), t("状态"), t("运行时长"),t("日期"), t("操作"),];
const job_headers = [t("名称"), t("状态"),t("cwd"),t("运行时长"), t("操作")];
Expand All @@ -66,6 +68,26 @@ export function WorkFlow(props) {
set_max_page_num(parseInt((pojo.total / page_size).toFixed(0)))
}

const search_run_name = async (search_name)=>{
const req = new WorkflowGetReq();
req.search_name = search_name;
req.dir_path = `${getRouterAfter('file', getRouterPath())}`
set_search_name_status(true);
const data:WsData<WorkflowGetRsq> = await ws.sendData(CmdType.workflow_search_by_run_name,req);
if(!data)return;
const pojo = data.context as WorkflowGetRsq;
// console.log(pojo.list)
set_task_rows(pojo.list.map(value => {
// @ts-ignore
const v = typeof value.meta === "string"?JSON.parse(value.meta):value.meta;
v.index = value.index;
return v}))
set_total(pojo.total);
set_max_page_num(parseInt((pojo.total / page_size).toFixed(0)))
set_page_num(0)
set_search_name_status(false);
}

const initTerminal = async () => {
const terminal = new Terminal({
// fontSize: 15,
Expand Down Expand Up @@ -216,40 +238,51 @@ export function WorkFlow(props) {
<CardFull self_title={<span className={" div-row "}><h2>{t("历史记录")}</h2>
{/*<ActionButton icon={"info"} onClick={()=>{soft_ware_info_click()}} title={"信息"}/>*/}
</span>}
titleCom={<div><ActionButton icon={"refresh"} title={t("刷新")} onClick={()=>{}}/></div>}
titleCom={<div className={" div-row "}>
<InputText
disabled={search_name_status}
value={search_name}
placeholder={"搜索运行名称(支持正则)"} handleInputChange={(v)=>{
set_search_name(search_name)
}}
handlerEnter={(v)=>{search_run_name(v)}}
/>
<ActionButton icon={"refresh"} title={t("刷新")} onClick={()=>{}}/>
</div>}
rightBottomCom={<span className={" div-row "}>
<span>total {total} </span>
<InputText placeholder={`max page ${max_page_num}`} handleInputChange={(v)=>{
<span>total {total} ;</span>
<span>now {Math.abs(page_num)} </span>
<InputText placeholder={`max page ${max_page_num}`} handleInputChange={(v) => {
input_page_num = parseInt(v);
}}
handlerEnter={()=>{
if(input_page_num<1 || input_page_num> max_page_num) {
NotyFail("illegal page num")
return;
}
get_page(0-input_page_num)
}}
handlerEnter={() => {
if (input_page_num < 1 || input_page_num > max_page_num) {
NotyFail("illegal page num")
return;
}
get_page(0 - input_page_num)
}}
/>
<ActionButton icon={"navigate_before"} onClick={()=>{
const n = page_num+1;
if(n>-1) {
<ActionButton icon={"navigate_before"} onClick={() => {
const n = page_num + 1;
if (n > -1) {
NotyFail("max page num")
return;
}
set_page_num(n)
get_page(n)
}} title={"上一页"}/>
<ActionButton icon={"navigate_next"} onClick={()=>{
const n = page_num-1;
if(Math.abs(n)>max_page_num) {
<ActionButton icon={"navigate_next"} onClick={() => {
const n = page_num - 1;
if (Math.abs(n) > max_page_num) {
NotyFail("min page num")
return
}
set_page_num(n)
get_page(n)
}} title={"下一页"}/>
</span>}>
<Table headers={task_headers} rows={task_rows.map((item, index) => {
<Table headers={task_headers} rows={task_rows.map((item, index) => {
let div;
if(item.is_running) {
div = <div><StatusCircle />{t('正在运行')}</div>
Expand All @@ -260,7 +293,9 @@ export function WorkFlow(props) {
}
const new_list = [
<p>{item.index}</p>,
<p>{item['run-name']}</p>,
<p style={{
wordWrap: 'break-word',
}}>{item['run-name']}</p>,
div,
<span>{item.duration}</span>,
<span>{item.timestamp}</span>,
Expand Down
4 changes: 4 additions & 0 deletions src/web/project/component/prompts/FileNew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ run-name: 构建项目 # 用于日志显示的名字
env: # 定义一些环境变量 这些 环境变量可以在 run 或者 cwd 中 或者 run-name 中使用 {{}} 来表达 使用的时候 必须要用 '' 字符串括起来,不然会被处理成变量 {{{ }}} 是非转义方式 采用 Mustache js
version: 1
cmd_install: npm install
# 有几个参数是每次执行自动添加的
# filecat_user_id: 1 # 用户id
# filecat_user_name: admin # 用户名字
# filecat_user_note: 备注 #用户备注
username: admin # 需要执行用户的账号 该脚本需要运行在某个用户下
user_id: 1 # 会覆盖 username 对应的用户 id 只允许特定设置的用户在这里可以被设置 运行
Expand Down

0 comments on commit bd4e5f1

Please sign in to comment.