This commit is contained in:
IDONTSUDO 2023-11-20 00:48:40 +03:00
parent d70253d6a6
commit fa645dde92
51 changed files with 657 additions and 281 deletions

View file

@ -17,6 +17,7 @@
},
"cSpell.words": [
"antd",
"fileupload",
"uuidv"
]
}

View file

@ -37,6 +37,7 @@
"concurrently": "^8.2.0",
"cors": "^2.8.5",
"express": "^4.18.2",
"express-fileupload": "^1.4.2",
"first-di": "^1.0.11",
"md5": "^2.3.0",
"mongoose": "^7.6.2",

View file

@ -1,13 +1,14 @@
import express from "express";
import { Routes } from "../interfaces/router";
import cors from "cors";
import mongoose from "mongoose";
import { Server } from "socket.io";
import { createServer } from "http";
import { SocketSubscriber } from "./socket_controller";
import { dirname } from "path";
import { CreateFolderUseCase } from "../usecases/crete_folder_usecase";
import { dirIsExists } from "../repository/fs";
import fileUpload from "express-fileupload";
import { SetLastActivePipelineToRealTimeServiceUseCase } from "../usecases/set_active_pipeline_to_realtime_service_usecase";
import { CheckAndCreateStaticFilesFolderUseCase } from "../usecases/check_and_create_static_files_folder_usecase";
import { DataBaseConnectUseCase } from "../usecases/database_connect_usecase";
export class App {
public app: express.Application;
@ -60,6 +61,11 @@ export class App {
this.app.use(express.json());
this.app.use(express.urlencoded({ extended: true }));
this.app.use(express.static("public"));
this.app.use(
fileUpload({
createParentPath: true,
})
);
}
private initializeRoutes(routes: Routes[]) {
@ -68,37 +74,11 @@ export class App {
});
}
async loadAppDependencies() {
// await locator(
// this.env == "development"
// ? new DevEnv(this.computedFolder)
// : new UnitTestEnv(this.computedFolder)
// );
await this.appStartController();
mongoose
.connect("mongodb://127.0.0.1:27017/test")
.then(() => {})
.catch((e) => {
console.log("ERROR:", e);
});
await new DataBaseConnectUseCase().call();
await new CheckAndCreateStaticFilesFolderUseCase().call();
await new SetLastActivePipelineToRealTimeServiceUseCase().call();
}
async appStartController() {
if (await dirIsExists(App.staticFilesStoreDir())) {
return;
}
const createFolderUseCase = await new CreateFolderUseCase().call(
App.staticFilesStoreDir()
);
createFolderUseCase.fold(
(_s) => {},
(e) => {
// TODO:(IDONTSUDO) need logger
console.log(e);
}
);
}
static staticFilesStoreDir = () => {
const dir = dirname(__filename);
const rootDir = dir.slice(0, dir.length - 20);

View file

@ -13,14 +13,19 @@ type Method =
| "options"
| "head";
export type CallbackStrategyWithValidationModel<T> = (
a: T
) => Promise<Result<any, any>>;
// TODO(IDOTSUDO):NEED IMPLEMENTS
// interface ISubSetFeatureRouter<T>{
// method:Method,
// fn:CallbackStrategyWithValidationModel<T>
// }
export type ResponseBase = Promise<Result<any, any>>;
// TODO(IDONTSUDO): rewrite the router for the strategy
export type CallbackStrategyWithEmpty = () => ResponseBase;
export type CallbackStrategyWithValidationModel<T> = (a: T) => ResponseBase;
export type CallbackStrategyWithIdQuery = (id: string) => ResponseBase;
export type CallBackStrategyWithQueryPage = (page: string) => ResponseBase;
export type CallbackStrategyWithFileUpload = (file: File) => ResponseBase;
interface ISubSetFeatureRouter<T> {
method: Method;
fn: CallbackStrategyWithValidationModel<T>;
}
abstract class ICoreHttpController {
abstract mainURL: string;
@ -31,6 +36,7 @@ abstract class ICoreHttpController {
export class CoreHttpController<V> implements ICoreHttpController {
mainURL: string;
validationModel: any;
subRoutes: ISubSetFeatureRouter<any>[] = [];
routes = {
POST: null,
@ -47,6 +53,11 @@ export class CoreHttpController<V> implements ICoreHttpController {
}
call(): Routes {
if (this.subRoutes.isNotEmpty()) {
this.subRoutes.map((el) => {
console.log(this.router[el.method]);
});
}
if (this.routes["POST"] != null) {
this.router.post(
this.mainURL,

View file

@ -1,44 +1,44 @@
import { Service } from "typedi";
// import { Service } from "typedi";
@Service()
export class IEnv{
rootFolder!: string;
constructor(){
// @Service()
// export class IEnv{
// rootFolder!: string;
// constructor(){
}
toStringEnv(){
return ''
}
static env(){
return ''
}
}
// }
// toStringEnv(){
// return ''
// }
// static env(){
// return ''
// }
// }
@Service()
export class DevEnv implements IEnv {
rootFolder:string;
constructor(rootFolder:string){
this.rootFolder = rootFolder
}
toStringEnv(): string {
return DevEnv.env()
}
static env(){
return 'DevEnv'
// @Service()
// export class DevEnv implements IEnv {
// rootFolder:string;
// constructor(rootFolder:string){
// this.rootFolder = rootFolder
// }
// toStringEnv(): string {
// return DevEnv.env()
// }
// static env(){
// return 'DevEnv'
}
}
@Service()
export class UnitTestEnv implements IEnv{
rootFolder:string;
constructor(rootFolder:string){
this.rootFolder = rootFolder
}
toStringEnv(): string {
return UnitTestEnv.env()
}
static env(){
return 'UnitTestEnv'
// }
// }
// @Service()
// export class UnitTestEnv implements IEnv{
// rootFolder:string;
// constructor(rootFolder:string){
// this.rootFolder = rootFolder
// }
// toStringEnv(): string {
// return UnitTestEnv.env()
// }
// static env(){
// return 'UnitTestEnv'
}
}
// }
// }

View file

@ -1,53 +1,53 @@
import { DevEnv, IEnv, UnitTestEnv } from "./env";
import { extensions } from "../extensions/extensions";
// import { Container, Service } from 'typedi';
// import { DevEnv, IEnv, UnitTestEnv } from "./env";
// import { extensions } from "../extensions/extensions";
// // import { Container, Service } from 'typedi';
export default function locator(env: IEnv) {
extensions();
envRegister(env);
registerRepository(env);
registerController(env);
registerService(env);
// override(MetaDataFileManagerModel, MetaDataFileManagerModel);
}
// export default function locator(env: IEnv) {
// extensions();
// envRegister(env);
// registerRepository(env);
// registerController(env);
// registerService(env);
// // override(MetaDataFileManagerModel, MetaDataFileManagerModel);
// }
const envRegister = (env: IEnv) => {
switch (env.toStringEnv()) {
case UnitTestEnv.env():
// override(IEnv, UnitTestEnv);
return;
case "DevEnv":
// override(IEnv, DevEnv);
return;
}
};
// const envRegister = (env: IEnv) => {
// switch (env.toStringEnv()) {
// case UnitTestEnv.env():
// // override(IEnv, UnitTestEnv);
// return;
// case "DevEnv":
// // override(IEnv, DevEnv);
// return;
// }
// };
const registerRepository = (env: IEnv) => {
switch (env.toStringEnv()) {
case UnitTestEnv.env():
// override(IEnv, UnitTestEnv);
// const registerRepository = (env: IEnv) => {
// switch (env.toStringEnv()) {
// case UnitTestEnv.env():
// // override(IEnv, UnitTestEnv);
return;
case DevEnv.env():
// override(IEnv, DevEnv);
return;
}
};
// return;
// case DevEnv.env():
// // override(IEnv, DevEnv);
// return;
// }
// };
const registerController = (env: IEnv) => {
switch (env.toStringEnv()) {
case UnitTestEnv.env():
return;
case DevEnv.env():
return;
}
};
// const registerController = (env: IEnv) => {
// switch (env.toStringEnv()) {
// case UnitTestEnv.env():
// return;
// case DevEnv.env():
// return;
// }
// };
const registerService = (env: IEnv) => {
switch (env.toStringEnv()) {
case UnitTestEnv.env():
return;
case DevEnv.env():
return;
}
};
// const registerService = (env: IEnv) => {
// switch (env.toStringEnv()) {
// case UnitTestEnv.env():
// return;
// case DevEnv.env():
// return;
// }
// };

View file

@ -1,25 +1,18 @@
export {};
declare global {
interface Array<T> {
// @strict: The parameter is determined whether the arrays must be exactly the same in content and order of this relationship or simply follow the same requirements.
equals(array: Array<T>, strict: boolean): boolean;
}
}
export const ArrayEquals = () => {
if ([].equals == undefined) {
/* eslint-disable @typescript-eslint/no-this-alias */
export const ArrayExtensions = () => {
if ([].equals === undefined) {
// eslint-disable-next-line no-extend-native
Array.prototype.equals = function (array, strict = true) {
if (!array) return false;
if (arguments.length == 1) strict = true;
if (arguments.length === 1) strict = true;
if (this.length != array.length) return false;
if (this.length !== array.length) return false;
for (let i = 0; i < this.length; i++) {
if (this[i] instanceof Array && array[i] instanceof Array) {
if (!this[i].equals(array[i], strict)) return false;
} else if (strict && this[i] != array[i]) {
} else if (strict && this[i] !== array[i]) {
return false;
} else if (!strict) {
return this.sort().equals(array.sort(), true);
@ -28,4 +21,27 @@ export const ArrayEquals = () => {
return true;
};
}
if ([].lastElement === undefined) {
// eslint-disable-next-line no-extend-native
Array.prototype.lastElement = function () {
const instanceCheck = this;
if (instanceCheck === undefined) {
return undefined;
} else {
const instance = instanceCheck as [];
return instance[instance.length - 1];
}
};
}
if ([].isEmpty === undefined) {
// eslint-disable-next-line no-extend-native
Array.prototype.isEmpty = function () {
return this.length === 0;
};
}
if ([].isNotEmpty === undefined) {
Array.prototype.isNotEmpty = function () {
return this.length !== 0;
};
}
};

View file

@ -1,6 +1,20 @@
import { ArrayEquals } from "./array";
import { ArrayExtensions } from "./array";
import { StringExtensions } from "./string";
export const extensions = () =>{
ArrayEquals()
declare global {
interface Array<T> {
// @strict: The parameter is determined whether the arrays must be exactly the same in content and order of this relationship or simply follow the same requirements.
equals(array: Array<T>, strict: boolean): boolean;
lastElement(): T | undefined;
isEmpty(): boolean;
isNotEmpty(): boolean;
}
interface String {
isEmpty(): boolean;
isNotEmpty(): boolean;
}
}
export const extensions = () => {
ArrayExtensions();
StringExtensions();
};

View file

@ -0,0 +1,14 @@
export const StringExtensions = () => {
if ("".isEmpty === undefined) {
// eslint-disable-next-line no-extend-native
String.prototype.isEmpty = function () {
return this.length === 0;
};
}
if ("".isNotEmpty === undefined) {
// eslint-disable-next-line no-extend-native
String.prototype.isNotEmpty = function () {
return this.length !== 0;
};
}
};

View file

@ -0,0 +1,20 @@
export class ActivePipeline {
pipelineIsRunning: boolean;
projectUUID?: string | null;
lastProcessCompleteCount: number | null;
error: any;
constructor(
pipelineIsRunning: boolean,
lastProcessCompleteCount: number | null,
error: any,
projectUUID?: string | null
) {
this.pipelineIsRunning = pipelineIsRunning;
this.projectUUID = projectUUID;
this.lastProcessCompleteCount = lastProcessCompleteCount;
this.error = error;
}
static empty() {
return new ActivePipeline(false, null, null, null);
}
}

View file

@ -1,24 +1,21 @@
import { TypedEvent } from "../helper/typed_event";
import { ExecError } from "../model/exec_error_model";
import { ExecutorResult } from "../model/executor_result";
import { IPipelineMeta } from "../model/pipeline_meta";
import { ActivePipeline } from "../model/active_pipeline_model";
import { IPipeline } from "../model/process_model";
import { Iteration, StackService } from "./stack_service";
export class PipelineRealTimeService extends TypedEvent<IPipelineMeta> {
status: IPipelineMeta;
export class PipelineRealTimeService extends TypedEvent<ActivePipeline> {
status: ActivePipeline;
pipelineModels?: IPipeline[];
path: string;
constructor() {
super();
this.init();
}
private init(): void {
this.status = {
pipelineIsRunning: false,
projectUUID: null,
lastProcessCompleteCount: null,
error: null,
};
this.status = ActivePipeline.empty();
}
pipelineSubscriber = (iterations: Iteration[]): void => {
if (this.status["lastProcessCompleteCount"] === 0) {
@ -65,16 +62,21 @@ export class PipelineRealTimeService extends TypedEvent<IPipelineMeta> {
this.status.pipelineIsRunning = false;
}
}
runPipeline(
setPipelineDependency(
pipelineModels: IPipeline[],
path: string,
projectUUID: string
): void {
const stack = new StackService(pipelineModels, path);
) {
this.pipelineModels = pipelineModels;
this.path = path;
this.status["projectUUID"] = projectUUID;
this.status["pipelineIsRunning"] = true;
stack.on(this.pipelineSubscriber);
stack.call();
}
runPipeline(): void {
// const stack = new StackService(this.pipelineModels, this.path);
// this.status["pipelineIsRunning"] = true;
// stack.on(this.pipelineSubscriber);
// stack.call();
}
}

View file

@ -0,0 +1,22 @@
import { App } from "../controllers/app";
import { dirIsExists } from "../repository/fs";
import { CreateFolderUseCase } from "./crete_folder_usecase";
export class CheckAndCreateStaticFilesFolderUseCase {
call = async (): Promise<void> => {
if (await dirIsExists(App.staticFilesStoreDir())) {
return;
}
const createFolderUseCase = await new CreateFolderUseCase().call(
App.staticFilesStoreDir()
);
createFolderUseCase.fold(
(_s) => {},
(e) => {
console.log(e);
}
);
};
}

View file

@ -0,0 +1,13 @@
import mongoose from "mongoose";
import { Result } from "../helper/result";
export class DataBaseConnectUseCase {
call = async (): Promise<Result<Error, void>> => {
try {
await mongoose.connect("mongodb://127.0.0.1:27017/test");
return Result.ok();
} catch (error) {
return Result.error(error as Error);
}
};
}

View file

@ -1,3 +1,18 @@
export class RegExpSearchDataBaseModelUseCase {
call = () => {};
import { Result } from "../helper/result";
export class SearchDataBaseModelUseCase<T> {
model: any;
constructor(model: any) {
this.model = model;
}
call = async (findFilter: Partial<T>): Promise<Result<null, T>> => {
const result = await this.model.findOne(findFilter);
if (result === null) {
return Result.error(null);
} else {
return Result.ok(result);
}
};
}

View file

@ -0,0 +1,26 @@
import {
IProjectInstanceModel,
ProjectInstanceDbModel,
} from "../../features/project_instance/project_instance_model";
import { pipelineRealTimeService } from "../../features/realtime/realtime_presentation";
import { App } from "../controllers/app";
import { SearchDataBaseModelUseCase } from "./search_database_model_usecase";
export class SetLastActivePipelineToRealTimeServiceUseCase {
call = async (): Promise<void> => {
const result = await new SearchDataBaseModelUseCase<IProjectInstanceModel>(
ProjectInstanceDbModel
).call({
isActive: true,
});
if (result.isSuccess()) {
const projectModel = result.value.project;
pipelineRealTimeService.setPipelineDependency(
projectModel.pipelines,
App.staticFilesStoreDir() + projectModel.rootDir + "/",
projectModel._id
);
}
};
}

View file

@ -1,8 +1,13 @@
import { IsMongoId, IsOptional } from "class-validator";
import { IsMongoId, IsOptional, ValidateNested } from "class-validator";
import { Schema, model } from "mongoose";
import { IProcess, StackGenerateType } from "../../core/model/process_model";
import {
IPipeline,
IProcess,
StackGenerateType,
} from "../../core/model/process_model";
import { TriggerModel, triggerSchema } from "../triggers/trigger_model";
import { schemaProcess } from "../process/process_model";
import { ProcessModel, schemaProcess } from "../process/process_model";
import { Type } from "class-transformer";
export const PipelineSchema = new Schema({
process: {
@ -17,21 +22,21 @@ export const PipelineSchema = new Schema({
autopopulate: true,
default: null,
},
stackGenerateType: {
type: String,
default: null,
},
}).plugin(require("mongoose-autopopulate"));
export const schemaPipeline = "Pipeline";
export const PipelineDBModel = model<PipelineModel>(
schemaPipeline,
PipelineSchema
);
export const PipelineDBModel = model<IPipeline>(schemaPipeline, PipelineSchema);
export class PipelineModel {
export class PipelineValidationModel {
@IsMongoId()
public process: IProcess;
@IsMongoId()
//TODO(IDONTSUDO):NEED OPTION DECORATOR??
public trigger: TriggerModel;
@IsOptional()
@ -40,3 +45,17 @@ export class PipelineModel {
@IsOptional()
public stackGenerateType: StackGenerateType;
}
export class PipelineModel implements IPipeline {
@ValidateNested()
@Type(() => ProcessModel)
public process: IProcess;
@ValidateNested()
@Type(() => TriggerModel)
public trigger: TriggerModel;
@IsOptional()
public env = null;
@IsOptional()
public stackGenerateType: StackGenerateType;
}

View file

@ -1,14 +1,14 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { PipelineDBModel, PipelineModel } from "./pipeline_model";
import { PipelineDBModel, PipelineValidationModel } from "./pipeline_model";
export class PipelinePresentation extends CrudController<
PipelineModel,
PipelineValidationModel,
typeof PipelineDBModel
> {
constructor() {
super({
url: "pipeline",
validationModel: PipelineModel,
validationModel: PipelineValidationModel,
databaseModel: PipelineDBModel,
});
}

View file

@ -2,11 +2,16 @@ import { App } from "../../core/controllers/app";
import { Result } from "../../core/helper/result";
import { CreateDataBaseModelUseCase } from "../../core/usecases/create_database_model_usecase";
import { CreateFolderUseCase } from "../../core/usecases/crete_folder_usecase";
import { ProjectDBModel, ProjectValidationModel } from "./projects_model";
import {
ProjectInstanceDbModel,
ProjectInstanceValidationModel,
} from "./project_instance_model";
import { v4 as uuidv4 } from "uuid";
export class CreateNewProjectScenario {
call = async (model: ProjectValidationModel): Promise<Result<Error, any>> => {
export class CreateNewProjectInstanceScenario {
call = async (
model: ProjectInstanceValidationModel
): Promise<Result<Error, any>> => {
try {
const folderName = uuidv4() + "/";
const createFolderUseCase = await new CreateFolderUseCase().call(
@ -15,10 +20,10 @@ export class CreateNewProjectScenario {
if (createFolderUseCase.isFailure()) {
return createFolderUseCase.forward();
}
model.rootDir = folderName;
const createDataBaseModelUseCase = await new CreateDataBaseModelUseCase(
ProjectDBModel
ProjectInstanceDbModel
).call(model);
if (createDataBaseModelUseCase.isFailure()) {

View file

@ -0,0 +1,45 @@
import { Schema, model } from "mongoose";
import { IProjectModel, projectSchema } from "../projects/projects_model";
import { IsMongoId, IsOptional, IsString } from "class-validator";
export interface IProjectInstanceModel {
project: IProjectModel;
description: string;
rootDir: string;
isActive: boolean;
}
export const ProjectInstanceSchema = new Schema({
project: {
type: Schema.Types.ObjectId,
ref: projectSchema,
autopopulate: true,
default: null,
},
description: {
type: String,
},
rootDir: {
type: String,
},
isActive: {
type: Boolean,
default: false,
},
}).plugin(require("mongoose-autopopulate"));
export const schemaProjectInstance = "instance_project";
export const ProjectInstanceDbModel = model<IProjectInstanceModel>(
schemaProjectInstance,
ProjectInstanceSchema
);
export class ProjectInstanceValidationModel {
@IsMongoId()
public project: string;
@IsString()
public description: string;
@IsOptional()
public rootDir: string;
}

View file

@ -0,0 +1,23 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { CreateNewProjectInstanceScenario } from "./create_new_project_scenario";
import {
ProjectInstanceDbModel,
ProjectInstanceValidationModel,
} from "./project_instance_model";
export class ProjectInstancePresentation extends CrudController<
ProjectInstanceValidationModel,
typeof ProjectInstanceDbModel
> {
constructor() {
super({
validationModel: ProjectInstanceValidationModel,
url: "project_instance",
databaseModel: ProjectInstanceDbModel,
});
super.post(new CreateNewProjectInstanceScenario().call);
// super.router.post(this.mainURL + "/file", (req, res) => {
// TODO:
// });
}
}

View file

@ -1,12 +1,13 @@
import { Schema, model } from "mongoose";
import { PipelineModel, schemaPipeline } from "../pipelines/pipeline_model";
import { IsArray, IsOptional, IsString } from "class-validator";
import { PipelineValidationModel, schemaPipeline } from "../pipelines/pipeline_model";
import { IsArray, IsString } from "class-validator";
export interface IProjectModel {
_id?:string;
pipelines: [PipelineModel];
_id?: string;
pipelines: [PipelineValidationModel];
rootDir: string;
description: string;
isActive:boolean;
}
export const ProjectSchema = new Schema({
@ -16,23 +17,23 @@ export const ProjectSchema = new Schema({
autopopulate: true,
default: null,
},
rootDir: {
type: String,
},
description: {
type: String,
},
isActive: {
type: Boolean,
default: false,
},
}).plugin(require("mongoose-autopopulate"));
const schema = "Projects";
export const projectSchema = "Projects";
export const ProjectDBModel = model<IProjectModel>(schema, ProjectSchema);
export const ProjectDBModel = model<IProjectModel>(projectSchema, ProjectSchema);
export class ProjectValidationModel {
@IsArray()
public pipelines: [string];
@IsString()
public description: string;
@IsOptional()
public rootDir: string;
}

View file

@ -1,5 +1,4 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { CreateNewProjectScenario } from "./create_new_project_scenario";
import { ProjectDBModel, ProjectValidationModel } from "./projects_model";
export class ProjectsPresentation extends CrudController<
@ -12,6 +11,5 @@ export class ProjectsPresentation extends CrudController<
validationModel: ProjectValidationModel,
databaseModel: ProjectDBModel,
});
super.post(new CreateNewProjectScenario().call);
}
}

View file

@ -1,9 +1,9 @@
import { Result } from "../../../core/helper/result";
import { IPipelineMeta } from "../../../core/model/pipeline_meta";
import { ActivePipeline } from "../../../core/model/active_pipeline_model";
import { pipelineRealTimeService } from "../realtime_presentation";
export class PipelineStatusUseCase {
async call(): Promise<Result<Error, IPipelineMeta>> {
async call(): Promise<Result<Error, ActivePipeline>> {
try {
return Result.ok(pipelineRealTimeService.status);
} catch (error) {

View file

@ -1,8 +1,11 @@
import { App } from "../../../core/controllers/app";
import { Result } from "../../../core/helper/result";
import { EXEC_TYPE } from "../../../core/model/exec_error_model";
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
import { IProjectModel, ProjectDBModel } from "../../projects/projects_model";
import { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase";
import {
IProjectInstanceModel,
ProjectInstanceDbModel,
} from "../../project_instance/project_instance_model";
import {
RealTimeValidationModel,
pipelineRealTimeService,
@ -10,29 +13,35 @@ import {
export class RunInstancePipelineUseCase {
async call(model: RealTimeValidationModel): Promise<Result<Error, any>> {
const id = model.id;
const { id } = model;
const readByIdDataBaseModelUseCase =
await new ReadByIdDataBaseModelUseCase<IProjectModel>(
ProjectDBModel
await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(
ProjectInstanceDbModel
).call(id);
if (readByIdDataBaseModelUseCase.isFailure()) {
return readByIdDataBaseModelUseCase.forward();
}
const projectModel = readByIdDataBaseModelUseCase.value;
projectModel.pipelines.map((el) => {
el.process.type = EXEC_TYPE.EXEC;
});
const projectModel = readByIdDataBaseModelUseCase.value.project;
projectModel.isActive = true;
pipelineRealTimeService.runPipeline(
const updateDataBaseModelUseCase = await new UpdateDataBaseModelUseCase<
IProjectInstanceModel,
any
>(ProjectInstanceDbModel).call(projectModel);
if (updateDataBaseModelUseCase.isFailure()) {
return updateDataBaseModelUseCase.forward();
}
pipelineRealTimeService.setPipelineDependency(
projectModel.pipelines,
App.staticFilesStoreDir() + projectModel.rootDir + "/",
projectModel._id
);
pipelineRealTimeService.runPipeline();
return Result.ok({ status: "ok" });
}
}
// /Users/idontsudo/Desktop/testdeck-mocha-seed/server/build/public/ce4e7710-73dc-47fc-87ee-d448ea2412ce
// new ObjectId("6554c22d2ef337587505a494")

View file

@ -10,6 +10,10 @@ import {
RealTimePresentation,
pipelineRealTimeService,
} from "./features/realtime/realtime_presentation";
import { extensions } from "./core/extensions/extensions";
import { ProjectInstancePresentation } from "./features/project_instance/project_instance_presentation";
extensions();
const httpRoutes: Routes[] = [
new TriggerPresentation(),
@ -17,6 +21,7 @@ const httpRoutes: Routes[] = [
new ProcessPresentation(),
new PipelinePresentation(),
new RealTimePresentation(),
new ProjectInstancePresentation(),
].map((el) => el.call());
const socketSubscribers = [
@ -24,4 +29,3 @@ const socketSubscribers = [
];
new App(httpRoutes, socketSubscribers).listen();

View file

@ -7,6 +7,6 @@ export class PipelineRealTimeServiceTest extends PipelineRealTimeService {
super();
}
async test() {
this.runPipeline(mockSimplePipeline, dirname__, "");
// this.runPipeline(mockSimplePipeline, dirname__, "");
}
}

5
server/todo.md Normal file
View file

@ -0,0 +1,5 @@
создание инстанца [ OK ]
получение всех инастанцев проектов и изменнение их [ OK ]
запуск инастанца проекта? [ OK ]
загрузка FILE [ ]

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-this-alias */
export const ArrayExtensions = () => {
if ([].equals === undefined) {
// eslint-disable-next-line no-extend-native
@ -23,11 +24,11 @@ export const ArrayExtensions = () => {
if ([].lastElement === undefined) {
// eslint-disable-next-line no-extend-native
Array.prototype.lastElement = function () {
let instanceCheck = this;
const instanceCheck = this;
if (instanceCheck === undefined) {
return undefined;
} else {
let instance = instanceCheck as [];
const instance = instanceCheck as [];
return instance[instance.length - 1];
}
};
@ -38,4 +39,10 @@ export const ArrayExtensions = () => {
return this.length === 0;
};
}
if ([].isNotEmpty === undefined) {
// eslint-disable-next-line no-extend-native
Array.prototype.isNotEmpty = function () {
return this.length !== 0;
};
}
};

View file

@ -7,6 +7,7 @@ declare global {
equals(array: Array<T>, strict: boolean): boolean;
lastElement(): T | undefined;
isEmpty(): boolean;
isNotEmpty():boolean;
}
interface String {
isEmpty(): boolean;

View file

@ -1,4 +1,5 @@
export interface IPipelineMeta {
export interface ActivePipeline {
pipelineIsRunning: boolean;
projectUUID?: string | null;
lastProcessCompleteCount: number | null;

View file

@ -23,15 +23,27 @@ import {
CreateTriggerScreenPath,
TriggerScreen,
} from "../../features/create_trigger/presentation/create_trigger_screen";
import { CreateProcessScreen, CreateProcessScreenPath } from "../../features/create_process/presentation/create_process_screen";
import {
CreateProcessScreen,
CreateProcessScreenPath,
} from "../../features/create_process/presentation/create_process_screen";
import { ProjectRepository } from "../../features/all_projects/data/project_repository";
import {
CreateProjectInstancePath,
CreateProjectInstanceScreen,
} from "../../features/create_project_instance/create_project_instance";
const idURL = ":id";
export const router = createBrowserRouter([
{
path: AllProjectScreenPath,
loader: new ProjectRepository().loader,
element: <AllProjectScreen />,
},
{
path: PipelineInstanceScreenPath,
path: PipelineInstanceScreenPath + idURL,
element: <PipelineInstanceScreen />,
},
{
@ -54,4 +66,8 @@ export const router = createBrowserRouter([
path: CreateProcessScreenPath,
element: <CreateProcessScreen />,
},
{
path: CreateProjectInstancePath + idURL,
element: <CreateProjectInstanceScreen />,
},
]);

View file

@ -0,0 +1,22 @@
// TODO(IDONTSUDO): нужно переписать все запросы под BaseStore
import { Result } from "../helper/result";
export class BaseStore {
isLoading = false;
isError = false;
async loadingHelper<T>(callBack: Promise<Result<any, T>>) {
this.isLoading = true;
const result = await callBack;
if (result.isFailure()) {
this.isError = true;
this.isLoading = false;
return result.forward();
}
this.isLoading = false;
return result;
}
}

View file

@ -8,7 +8,7 @@ import { useNavigate } from "react-router-dom";
const { Title } = Typography;
export interface IHeader {
largeText: string;
largeText?: string;
minText?: string;
path?: string;
needBackButton?: undefined | any;

View file

@ -1,8 +1,27 @@
import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository";
import { redirect } from "react-router-dom";
import { ActivePipeline } from "../../../core/model/active_pipiline";
import {
HttpMethod,
HttpRepository,
} from "../../../core/repository/http_repository";
import { PipelineInstanceScreenPath } from "../../pipeline_instance_main_screen/pipeline_instance_screen";
import { IProjectModel } from "../model/project_model";
export class ProjectRepository extends HttpRepository {
async getAllProject() {
return this.jsonRequest<IProjectModel[]>(HttpMethod.GET,'/project')
return this.jsonRequest<IProjectModel[]>(HttpMethod.GET, "/project");
}
async getActivePipeline() {
return this.jsonRequest<ActivePipeline>(HttpMethod.GET, "/realtime");
}
loader = async () => {
const result = await this.getActivePipeline();
// if (result.isSuccess() && result.value.projectUUID !== null) {
// return redirect(PipelineInstanceScreenPath + result.value.projectUUID);
// }
return null;
};
}

View file

@ -15,7 +15,6 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
return (
<>
<LoadPage
largeText={"Projects"}
needBackButton={false}
minText="create project?"

View file

@ -1,42 +1,24 @@
import makeAutoObservable from "mobx-store-inheritance";
import { ProjectRepository } from "../data/project_repository";
import { IProjectModel } from "../model/project_model";
import { Result } from "../../../core/helper/result";
import { BaseStore } from "../../../core/store/base_store";
// TODO(IDONTSUDO): нужно переписать все сторы под BaseStore
class BaseStore {
isLoading = false;
isError = false;
async loadingHelper<T>(callBack: Promise<Result<any, T>>) {
this.isLoading = true;
const result = await callBack;
if (result.isFailure()) {
this.isError = true;
this.isLoading = false;
return result.forward();
}
this.isLoading = false;
return result;
}
}
export class AllProjectStore extends BaseStore {
projectsModels?: IProjectModel[];
repository: ProjectRepository;
redirect = false;
constructor(repository: ProjectRepository) {
super();
this.repository = repository;
this.getProjects();
makeAutoObservable(this);
}
async getProjects() {
const result = await this.loadingHelper(this.repository.getAllProject());
if (result.isSuccess()) {
this.projectsModels = result.value;
}
}
}

View file

@ -1,8 +1,9 @@
import { makeAutoObservable } from "mobx";
import makeAutoObservable from "mobx-store-inheritance";
import { CreatePipelineRepository } from "../data/create_pipeline_repository";
import { ITriggerModel } from "../../../core/model/trigger_model";
import { IProcess } from "../../create_process/model/process_model";
import { message } from "antd";
import { BaseStore } from "../../../core/store/base_store";
enum Type {
PROCESS,
@ -15,20 +16,23 @@ export interface UnionView {
uuid?: string;
}
export class CreatePipelineStore {
export class CreatePipelineStore extends BaseStore {
repository: CreatePipelineRepository;
triggersModels: ITriggerModel[] = [];
processModels: IProcess[] = [];
pipelineViewModels: UnionView[] = [];
isLoading = false;
isError = false;
constructor(repository: CreatePipelineRepository) {
super();
this.repository = repository;
makeAutoObservable(this);
this.init();
}
private init() {
this.loadTriggers();
this.loadProcess();
}
filterPipelineViewModel(index: number): void {
this.pipelineViewModels = this.pipelineViewModels.filter(
(_el, i) => i !== index

View file

@ -1,19 +1,20 @@
import { makeAutoObservable } from "mobx";
import makeAutoObservable from "mobx-store-inheritance";
import {
CreateProjectRepository,
PipelineModel,
} from "./create_project_repository";
import { message } from "antd";
import { BaseStore } from "../../core/store/base_store";
class CreateProjectStore {
class CreateProjectStore extends BaseStore {
repository: CreateProjectRepository;
isLoading = false;
isError = false;
pipelineModels?: PipelineModel[];
newProjectDescription: string = "";
newProjectViews: PipelineModel[] = [];
constructor(repository: CreateProjectRepository) {
super();
this.repository = repository;
makeAutoObservable(this);
this.loadPipelines();
@ -74,4 +75,3 @@ class CreateProjectStore {
export const createProjectStore = new CreateProjectStore(
new CreateProjectRepository()
);

View file

@ -0,0 +1,27 @@
import * as React from "react";
import { CreateProjectInstanceStore } from "./create_project_instance_store";
import { CreateProjectInstanceRepository } from "./create_project_instance_repository";
import { observer } from "mobx-react-lite";
import { Upload, Button } from "antd";
import { useParams } from "react-router-dom";
export const CreateProjectInstancePath = "/create/project/instance/";
export const CreateProjectInstanceScreen = observer(() => {
const [createProjectInstanceStore] = React.useState(
() => new CreateProjectInstanceStore(new CreateProjectInstanceRepository())
);
const id = useParams().id;
createProjectInstanceStore.getProjectById(id as string)
return (
<>
<Upload
onChange={(e) => {
console.log(e);
}}
>
<Button>Upload root entity</Button>
</Upload>
</>
);
});

View file

@ -0,0 +1,10 @@
import {
HttpMethod,
HttpRepository,
} from "../../core/repository/http_repository";
export class CreateProjectInstanceRepository extends HttpRepository {
async getProjectInstance(id: string) {
return await this.jsonRequest(HttpMethod.GET, "");
}
}

View file

@ -0,0 +1,18 @@
import makeAutoObservable from "mobx-store-inheritance";
import { BaseStore } from "../../core/store/base_store";
import { CreateProjectInstanceRepository } from "./create_project_instance_repository";
export class CreateProjectInstanceStore extends BaseStore {
constructor(repository: CreateProjectInstanceRepository) {
super();
this.repository = repository;
makeAutoObservable(this);
}
repository: CreateProjectInstanceRepository;
async getProjectById(id: string) {
const result = await this.loadingHelper(this.repository.getProjectInstance(id))
if(result.isSuccess()){
}
}
}

View file

@ -1,17 +1,18 @@
import { makeAutoObservable } from "mobx";
import makeAutoObservable from "mobx-store-inheritance";
import { v4 as uuidv4 } from "uuid";
import { TriggerType } from "../../../core/model/trigger_model";
import { TriggerRepository } from "../data/trigger_repository";
import { TriggerViewModel } from "../model/trigger_form_view_model";
import { BaseStore } from "../../../core/store/base_store";
class TriggerStore {
class TriggerStore extends BaseStore {
constructor(repository: TriggerRepository) {
super();
this.triggerType = TriggerType.FILE;
this.repository = repository;
makeAutoObservable(this);
}
isLoading = false;
triggerDescription: string = "";
triggerType: TriggerType;
codeTriggerValue = "";
@ -71,7 +72,7 @@ class TriggerStore {
}
}
async saveResult(): Promise<void> {
this.isLoading = true
this.isLoading = true;
await this.repository.save({
type: this.getTriggerDescription(),
description: this.triggerDescription,
@ -79,7 +80,7 @@ class TriggerStore {
return el.value;
}),
});
this.isLoading = false
this.isLoading = false;
}
}

View file

@ -0,0 +1 @@
export class PipelineInstanceRepository {}

View file

@ -1,14 +1,19 @@
import * as React from "react";
import { Button } from "antd";
import { LoadPage } from "../../core/ui/pages/load_page";
import { PipelineInstanceStore } from "./pipeline_instance_store";
export const PipelineInstanceScreenPath = '/pipeline_instance/:id'
export const PipelineInstanceScreenPath = "/pipeline_instance/";
export const PipelineInstanceScreen: React.FunctionComponent = () => {
return (
<>
const [pipelineInstanceStore] = React.useState(
() => new PipelineInstanceStore()
);
<Button></Button>
</>
return (
<LoadPage
needBackButton={false}
isError={pipelineInstanceStore.isError}
isLoading={pipelineInstanceStore.isLoading}
children={<div></div>}
/>
);
};

View file

@ -0,0 +1,9 @@
import makeAutoObservable from "mobx-store-inheritance";
import { BaseStore } from "../../core/store/base_store";
export class PipelineInstanceStore extends BaseStore {
constructor() {
super();
makeAutoObservable(this);
}
}

View file

@ -1,6 +1,7 @@
import { DatabaseModel } from "../../../core/model/database_model";
import { IProcess } from "../../create_process/model/process_model";
export interface IProjectModel {
export interface IProjectModel extends DatabaseModel {
pipelines: [IProcess];
rootDir: string;
description: string;

View file

@ -1,17 +1,19 @@
import * as React from "react";
import { observer } from "mobx-react-lite";
import { LoadPage } from "../../../core/ui/pages/load_page";
import { CreateProjectScreenPath } from "../../create_project/create_project_screen";
import { SelectProjectStore } from "./select_project_store";
import { SelectProjectRepository } from "../data/select_project_repository";
import { useNavigate } from "react-router-dom";
import { CreateProjectInstancePath } from "../../create_project_instance/create_project_instance";
import { Button } from "antd";
export const SelectProjectScreenPath = "/select_project";
export const SelectProjectScreen: React.FunctionComponent = observer(() => {
const [selectProjectStore] = React.useState(
() => new SelectProjectStore(new SelectProjectRepository())
);
const navigate = useNavigate();
return (
<>
@ -25,7 +27,13 @@ export const SelectProjectScreen: React.FunctionComponent = observer(() => {
return (
<>
<div>{el.description}</div>
<div>+(РЕАЛИЗУЙ ТУТ ПЛЮСИК БЛЯТЬ ИЛИ КНОПКУ)</div>
<div>
<Button
onClick={() => navigate(CreateProjectInstancePath + el._id)}
>
create instance
</Button>
</div>
</>
);
})}

View file

@ -1,15 +1,16 @@
import { makeAutoObservable } from "mobx";
import makeAutoObservable from "mobx-store-inheritance";
import { SelectProjectRepository } from "../data/select_project_repository";
import { IProjectModel } from "../model/project_model";
import { BaseStore } from "../../../core/store/base_store";
export class SelectProjectStore {
export class SelectProjectStore extends BaseStore {
repository: SelectProjectRepository;
isLoading = false;
isError = false;
page = 1;
projects: IProjectModel[] = [];
constructor(repository: SelectProjectRepository) {
super()
this.repository = repository;
makeAutoObservable(this);
this.getPipelines();

View file

@ -10,7 +10,7 @@ export interface ISocketListerProps {
export const SocketLister = observer((props: ISocketListerProps) => {
return (
<>
{socketListerStore.socketDisconnect ? (
{socketListerStore.socketHasDisconnect ? (
<ReloadIcon
onClick={() => {
socketListerStore.reconnect();

View file

@ -3,7 +3,7 @@ import { SocketRepository } from "../../core/repository/socket_repository";
class SocketListerStore {
repository: SocketRepository;
socketDisconnect = false;
socketHasDisconnect = false;
constructor(repository: SocketRepository) {
this.repository = repository;
@ -13,7 +13,7 @@ class SocketListerStore {
async reconnect() {
await this.repository.connect()
this.socketDisconnect = false
this.socketHasDisconnect = false
}
}