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": [ "cSpell.words": [
"antd", "antd",
"fileupload",
"uuidv" "uuidv"
] ]
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,25 +1,18 @@
export {}; /* eslint-disable @typescript-eslint/no-this-alias */
export const ArrayExtensions = () => {
declare global { if ([].equals === undefined) {
interface Array<T> { // eslint-disable-next-line no-extend-native
// @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) {
Array.prototype.equals = function (array, strict = true) { Array.prototype.equals = function (array, strict = true) {
if (!array) return false; 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++) { for (let i = 0; i < this.length; i++) {
if (this[i] instanceof Array && array[i] instanceof Array) { if (this[i] instanceof Array && array[i] instanceof Array) {
if (!this[i].equals(array[i], strict)) return false; 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; return false;
} else if (!strict) { } else if (!strict) {
return this.sort().equals(array.sort(), true); return this.sort().equals(array.sort(), true);
@ -28,4 +21,27 @@ export const ArrayEquals = () => {
return true; 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 = () =>{ declare global {
ArrayEquals() 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 { TypedEvent } from "../helper/typed_event";
import { ExecError } from "../model/exec_error_model"; import { ExecError } from "../model/exec_error_model";
import { ExecutorResult } from "../model/executor_result"; 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 { IPipeline } from "../model/process_model";
import { Iteration, StackService } from "./stack_service"; import { Iteration, StackService } from "./stack_service";
export class PipelineRealTimeService extends TypedEvent<IPipelineMeta> { export class PipelineRealTimeService extends TypedEvent<ActivePipeline> {
status: IPipelineMeta; status: ActivePipeline;
pipelineModels?: IPipeline[]; pipelineModels?: IPipeline[];
path: string;
constructor() { constructor() {
super(); super();
this.init(); this.init();
} }
private init(): void { private init(): void {
this.status = { this.status = ActivePipeline.empty();
pipelineIsRunning: false,
projectUUID: null,
lastProcessCompleteCount: null,
error: null,
};
} }
pipelineSubscriber = (iterations: Iteration[]): void => { pipelineSubscriber = (iterations: Iteration[]): void => {
if (this.status["lastProcessCompleteCount"] === 0) { if (this.status["lastProcessCompleteCount"] === 0) {
@ -65,16 +62,21 @@ export class PipelineRealTimeService extends TypedEvent<IPipelineMeta> {
this.status.pipelineIsRunning = false; this.status.pipelineIsRunning = false;
} }
} }
setPipelineDependency(
runPipeline(
pipelineModels: IPipeline[], pipelineModels: IPipeline[],
path: string, path: string,
projectUUID: string projectUUID: string
): void { ) {
const stack = new StackService(pipelineModels, path); this.pipelineModels = pipelineModels;
this.path = path;
this.status["projectUUID"] = projectUUID; this.status["projectUUID"] = projectUUID;
this.status["pipelineIsRunning"] = true; }
stack.on(this.pipelineSubscriber); runPipeline(): void {
stack.call();
// 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 { import { Result } from "../helper/result";
call = () => {};
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 { 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 { 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({ export const PipelineSchema = new Schema({
process: { process: {
@ -17,21 +22,21 @@ export const PipelineSchema = new Schema({
autopopulate: true, autopopulate: true,
default: null, default: null,
}, },
stackGenerateType: {
type: String,
default: null,
},
}).plugin(require("mongoose-autopopulate")); }).plugin(require("mongoose-autopopulate"));
export const schemaPipeline = "Pipeline"; export const schemaPipeline = "Pipeline";
export const PipelineDBModel = model<PipelineModel>( export const PipelineDBModel = model<IPipeline>(schemaPipeline, PipelineSchema);
schemaPipeline,
PipelineSchema
);
export class PipelineModel { export class PipelineValidationModel {
@IsMongoId() @IsMongoId()
public process: IProcess; public process: IProcess;
@IsMongoId() @IsMongoId()
//TODO(IDONTSUDO):NEED OPTION DECORATOR??
public trigger: TriggerModel; public trigger: TriggerModel;
@IsOptional() @IsOptional()
@ -40,3 +45,17 @@ export class PipelineModel {
@IsOptional() @IsOptional()
public stackGenerateType: StackGenerateType; 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 { CrudController } from "../../core/controllers/crud_controller";
import { PipelineDBModel, PipelineModel } from "./pipeline_model"; import { PipelineDBModel, PipelineValidationModel } from "./pipeline_model";
export class PipelinePresentation extends CrudController< export class PipelinePresentation extends CrudController<
PipelineModel, PipelineValidationModel,
typeof PipelineDBModel typeof PipelineDBModel
> { > {
constructor() { constructor() {
super({ super({
url: "pipeline", url: "pipeline",
validationModel: PipelineModel, validationModel: PipelineValidationModel,
databaseModel: PipelineDBModel, databaseModel: PipelineDBModel,
}); });
} }

View file

@ -2,11 +2,16 @@ import { App } from "../../core/controllers/app";
import { Result } from "../../core/helper/result"; import { Result } from "../../core/helper/result";
import { CreateDataBaseModelUseCase } from "../../core/usecases/create_database_model_usecase"; import { CreateDataBaseModelUseCase } from "../../core/usecases/create_database_model_usecase";
import { CreateFolderUseCase } from "../../core/usecases/crete_folder_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"; import { v4 as uuidv4 } from "uuid";
export class CreateNewProjectScenario { export class CreateNewProjectInstanceScenario {
call = async (model: ProjectValidationModel): Promise<Result<Error, any>> => { call = async (
model: ProjectInstanceValidationModel
): Promise<Result<Error, any>> => {
try { try {
const folderName = uuidv4() + "/"; const folderName = uuidv4() + "/";
const createFolderUseCase = await new CreateFolderUseCase().call( const createFolderUseCase = await new CreateFolderUseCase().call(
@ -15,10 +20,10 @@ export class CreateNewProjectScenario {
if (createFolderUseCase.isFailure()) { if (createFolderUseCase.isFailure()) {
return createFolderUseCase.forward(); return createFolderUseCase.forward();
} }
model.rootDir = folderName; model.rootDir = folderName;
const createDataBaseModelUseCase = await new CreateDataBaseModelUseCase( const createDataBaseModelUseCase = await new CreateDataBaseModelUseCase(
ProjectDBModel ProjectInstanceDbModel
).call(model); ).call(model);
if (createDataBaseModelUseCase.isFailure()) { 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 { Schema, model } from "mongoose";
import { PipelineModel, schemaPipeline } from "../pipelines/pipeline_model"; import { PipelineValidationModel, schemaPipeline } from "../pipelines/pipeline_model";
import { IsArray, IsOptional, IsString } from "class-validator"; import { IsArray, IsString } from "class-validator";
export interface IProjectModel { export interface IProjectModel {
_id?:string; _id?: string;
pipelines: [PipelineModel]; pipelines: [PipelineValidationModel];
rootDir: string; rootDir: string;
description: string; description: string;
isActive:boolean;
} }
export const ProjectSchema = new Schema({ export const ProjectSchema = new Schema({
@ -16,23 +17,23 @@ export const ProjectSchema = new Schema({
autopopulate: true, autopopulate: true,
default: null, default: null,
}, },
rootDir: {
type: String,
},
description: { description: {
type: String, type: String,
}, },
isActive: {
type: Boolean,
default: false,
},
}).plugin(require("mongoose-autopopulate")); }).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 { export class ProjectValidationModel {
@IsArray() @IsArray()
public pipelines: [string]; public pipelines: [string];
@IsString() @IsString()
public description: string; public description: string;
@IsOptional()
public rootDir: string;
} }

View file

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

View file

@ -3,7 +3,7 @@ import { CoreHttpController } from "../../core/controllers/http_controller";
import { PipelineRealTimeService } from "../../core/services/pipeline_real_time_service"; import { PipelineRealTimeService } from "../../core/services/pipeline_real_time_service";
import { RunInstancePipelineUseCase } from "./usecases/run_instance_pipeline_usecase"; import { RunInstancePipelineUseCase } from "./usecases/run_instance_pipeline_usecase";
import { PipelineStatusUseCase } from "./usecases/pipeline_status_usecase"; import { PipelineStatusUseCase } from "./usecases/pipeline_status_usecase";
export const pipelineRealTimeService = new PipelineRealTimeService(); export const pipelineRealTimeService = new PipelineRealTimeService();
export class RealTimeValidationModel { export class RealTimeValidationModel {

View file

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

View file

@ -1,8 +1,11 @@
import { App } from "../../../core/controllers/app"; import { App } from "../../../core/controllers/app";
import { Result } from "../../../core/helper/result"; 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 { 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 { import {
RealTimeValidationModel, RealTimeValidationModel,
pipelineRealTimeService, pipelineRealTimeService,
@ -10,29 +13,35 @@ import {
export class RunInstancePipelineUseCase { export class RunInstancePipelineUseCase {
async call(model: RealTimeValidationModel): Promise<Result<Error, any>> { async call(model: RealTimeValidationModel): Promise<Result<Error, any>> {
const id = model.id; const { id } = model;
const readByIdDataBaseModelUseCase = const readByIdDataBaseModelUseCase =
await new ReadByIdDataBaseModelUseCase<IProjectModel>( await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(
ProjectDBModel ProjectInstanceDbModel
).call(id); ).call(id);
if (readByIdDataBaseModelUseCase.isFailure()) { if (readByIdDataBaseModelUseCase.isFailure()) {
return readByIdDataBaseModelUseCase.forward(); return readByIdDataBaseModelUseCase.forward();
} }
const projectModel = readByIdDataBaseModelUseCase.value; const projectModel = readByIdDataBaseModelUseCase.value.project;
projectModel.pipelines.map((el) => { projectModel.isActive = true;
el.process.type = EXEC_TYPE.EXEC;
}); const updateDataBaseModelUseCase = await new UpdateDataBaseModelUseCase<
IProjectInstanceModel,
pipelineRealTimeService.runPipeline( any
>(ProjectInstanceDbModel).call(projectModel);
if (updateDataBaseModelUseCase.isFailure()) {
return updateDataBaseModelUseCase.forward();
}
pipelineRealTimeService.setPipelineDependency(
projectModel.pipelines, projectModel.pipelines,
App.staticFilesStoreDir() + projectModel.rootDir + "/", App.staticFilesStoreDir() + projectModel.rootDir + "/",
projectModel._id projectModel._id
); );
pipelineRealTimeService.runPipeline();
return Result.ok({ status: "ok" }); 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,13 +10,18 @@ import {
RealTimePresentation, RealTimePresentation,
pipelineRealTimeService, pipelineRealTimeService,
} from "./features/realtime/realtime_presentation"; } from "./features/realtime/realtime_presentation";
import { extensions } from "./core/extensions/extensions";
import { ProjectInstancePresentation } from "./features/project_instance/project_instance_presentation";
extensions();
const httpRoutes: Routes[] = [ const httpRoutes: Routes[] = [
new TriggerPresentation(), new TriggerPresentation(),
new ProjectsPresentation(), new ProjectsPresentation(),
new ProcessPresentation(), new ProcessPresentation(),
new PipelinePresentation(), new PipelinePresentation(),
new RealTimePresentation(), new RealTimePresentation(),
new ProjectInstancePresentation(),
].map((el) => el.call()); ].map((el) => el.call());
const socketSubscribers = [ const socketSubscribers = [
@ -24,4 +29,3 @@ const socketSubscribers = [
]; ];
new App(httpRoutes, socketSubscribers).listen(); new App(httpRoutes, socketSubscribers).listen();

View file

@ -7,6 +7,6 @@ export class PipelineRealTimeServiceTest extends PipelineRealTimeService {
super(); super();
} }
async test() { 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 = () => { export const ArrayExtensions = () => {
if ([].equals === undefined) { if ([].equals === undefined) {
// eslint-disable-next-line no-extend-native // eslint-disable-next-line no-extend-native
@ -23,11 +24,11 @@ export const ArrayExtensions = () => {
if ([].lastElement === undefined) { if ([].lastElement === undefined) {
// eslint-disable-next-line no-extend-native // eslint-disable-next-line no-extend-native
Array.prototype.lastElement = function () { Array.prototype.lastElement = function () {
let instanceCheck = this; const instanceCheck = this;
if (instanceCheck === undefined) { if (instanceCheck === undefined) {
return undefined; return undefined;
} else { } else {
let instance = instanceCheck as []; const instance = instanceCheck as [];
return instance[instance.length - 1]; return instance[instance.length - 1];
} }
}; };
@ -38,4 +39,10 @@ export const ArrayExtensions = () => {
return this.length === 0; 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; equals(array: Array<T>, strict: boolean): boolean;
lastElement(): T | undefined; lastElement(): T | undefined;
isEmpty(): boolean; isEmpty(): boolean;
isNotEmpty():boolean;
} }
interface String { interface String {
isEmpty(): boolean; isEmpty(): boolean;

View file

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

View file

@ -23,15 +23,27 @@ import {
CreateTriggerScreenPath, CreateTriggerScreenPath,
TriggerScreen, TriggerScreen,
} from "../../features/create_trigger/presentation/create_trigger_screen"; } 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([ export const router = createBrowserRouter([
{ {
path: AllProjectScreenPath, path: AllProjectScreenPath,
loader: new ProjectRepository().loader,
element: <AllProjectScreen />, element: <AllProjectScreen />,
}, },
{ {
path: PipelineInstanceScreenPath, path: PipelineInstanceScreenPath + idURL,
element: <PipelineInstanceScreen />, element: <PipelineInstanceScreen />,
}, },
{ {
@ -54,4 +66,8 @@ export const router = createBrowserRouter([
path: CreateProcessScreenPath, path: CreateProcessScreenPath,
element: <CreateProcessScreen />, 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; const { Title } = Typography;
export interface IHeader { export interface IHeader {
largeText: string; largeText?: string;
minText?: string; minText?: string;
path?: string; path?: string;
needBackButton?: undefined | any; needBackButton?: undefined | any;
@ -25,7 +25,7 @@ export const Header: React.FunctionComponent<IHeader> = (props: IHeader) => {
marginTop: "20px", marginTop: "20px",
marginRight: "20px", marginRight: "20px",
display: "contents", display: "contents",
}} }}
> >
{needBackButton ? ( {needBackButton ? (
<> <>

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"; import { IProjectModel } from "../model/project_model";
export class ProjectRepository extends HttpRepository { export class ProjectRepository extends HttpRepository {
async getAllProject() { 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

@ -6,7 +6,7 @@ import { observer } from "mobx-react-lite";
import { SelectProjectScreenPath } from "../../select_project/presentation/select_project"; import { SelectProjectScreenPath } from "../../select_project/presentation/select_project";
export const AllProjectScreenPath = "/"; export const AllProjectScreenPath = "/";
export const AllProjectScreen: React.FunctionComponent = observer(() => { export const AllProjectScreen: React.FunctionComponent = observer(() => {
const [allProjectStore] = React.useState( const [allProjectStore] = React.useState(
() => new AllProjectStore(new ProjectRepository()) () => new AllProjectStore(new ProjectRepository())
@ -15,7 +15,6 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
return ( return (
<> <>
<LoadPage <LoadPage
largeText={"Projects"} largeText={"Projects"}
needBackButton={false} needBackButton={false}
minText="create project?" minText="create project?"

View file

@ -1,42 +1,24 @@
import makeAutoObservable from "mobx-store-inheritance"; import makeAutoObservable from "mobx-store-inheritance";
import { ProjectRepository } from "../data/project_repository"; import { ProjectRepository } from "../data/project_repository";
import { IProjectModel } from "../model/project_model"; 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 { export class AllProjectStore extends BaseStore {
projectsModels?: IProjectModel[]; projectsModels?: IProjectModel[];
repository: ProjectRepository; repository: ProjectRepository;
redirect = false;
constructor(repository: ProjectRepository) { constructor(repository: ProjectRepository) {
super(); super();
this.repository = repository; this.repository = repository;
this.getProjects();
makeAutoObservable(this); makeAutoObservable(this);
} }
async getProjects() { async getProjects() {
const result = await this.loadingHelper(this.repository.getAllProject()); const result = await this.loadingHelper(this.repository.getAllProject());
if (result.isSuccess()) { if (result.isSuccess()) {
this.projectsModels = result.value; this.projectsModels = result.value;
} }
} }
}
}

View file

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

View file

@ -1,19 +1,20 @@
import { makeAutoObservable } from "mobx"; import makeAutoObservable from "mobx-store-inheritance";
import { import {
CreateProjectRepository, CreateProjectRepository,
PipelineModel, PipelineModel,
} from "./create_project_repository"; } from "./create_project_repository";
import { message } from "antd"; import { message } from "antd";
import { BaseStore } from "../../core/store/base_store";
class CreateProjectStore { class CreateProjectStore extends BaseStore {
repository: CreateProjectRepository; repository: CreateProjectRepository;
isLoading = false;
isError = false;
pipelineModels?: PipelineModel[]; pipelineModels?: PipelineModel[];
newProjectDescription: string = ""; newProjectDescription: string = "";
newProjectViews: PipelineModel[] = []; newProjectViews: PipelineModel[] = [];
constructor(repository: CreateProjectRepository) { constructor(repository: CreateProjectRepository) {
super();
this.repository = repository; this.repository = repository;
makeAutoObservable(this); makeAutoObservable(this);
this.loadPipelines(); this.loadPipelines();
@ -74,4 +75,3 @@ class CreateProjectStore {
export const createProjectStore = new CreateProjectStore( export const createProjectStore = new CreateProjectStore(
new CreateProjectRepository() 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 { v4 as uuidv4 } from "uuid";
import { TriggerType } from "../../../core/model/trigger_model"; import { TriggerType } from "../../../core/model/trigger_model";
import { TriggerRepository } from "../data/trigger_repository"; import { TriggerRepository } from "../data/trigger_repository";
import { TriggerViewModel } from "../model/trigger_form_view_model"; import { TriggerViewModel } from "../model/trigger_form_view_model";
import { BaseStore } from "../../../core/store/base_store";
class TriggerStore { class TriggerStore extends BaseStore {
constructor(repository: TriggerRepository) { constructor(repository: TriggerRepository) {
super();
this.triggerType = TriggerType.FILE; this.triggerType = TriggerType.FILE;
this.repository = repository; this.repository = repository;
makeAutoObservable(this); makeAutoObservable(this);
} }
isLoading = false;
triggerDescription: string = ""; triggerDescription: string = "";
triggerType: TriggerType; triggerType: TriggerType;
codeTriggerValue = ""; codeTriggerValue = "";
@ -71,7 +72,7 @@ class TriggerStore {
} }
} }
async saveResult(): Promise<void> { async saveResult(): Promise<void> {
this.isLoading = true this.isLoading = true;
await this.repository.save({ await this.repository.save({
type: this.getTriggerDescription(), type: this.getTriggerDescription(),
description: this.triggerDescription, description: this.triggerDescription,
@ -79,7 +80,7 @@ class TriggerStore {
return el.value; 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 * 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/";
export const PipelineInstanceScreenPath = '/pipeline_instance/:id'
export const PipelineInstanceScreen: React.FunctionComponent = () => { export const PipelineInstanceScreen: React.FunctionComponent = () => {
const [pipelineInstanceStore] = React.useState(
() => new PipelineInstanceStore()
);
return ( return (
<> <LoadPage
needBackButton={false}
<Button></Button> 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"; import { IProcess } from "../../create_process/model/process_model";
export interface IProjectModel { export interface IProjectModel extends DatabaseModel {
pipelines: [IProcess]; pipelines: [IProcess];
rootDir: string; rootDir: string;
description: string; description: string;

View file

@ -1,17 +1,19 @@
import * as React from "react"; import * as React from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { LoadPage } from "../../../core/ui/pages/load_page"; import { LoadPage } from "../../../core/ui/pages/load_page";
import { CreateProjectScreenPath } from "../../create_project/create_project_screen"; import { CreateProjectScreenPath } from "../../create_project/create_project_screen";
import { SelectProjectStore } from "./select_project_store"; import { SelectProjectStore } from "./select_project_store";
import { SelectProjectRepository } from "../data/select_project_repository"; 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 SelectProjectScreenPath = "/select_project";
export const SelectProjectScreen: React.FunctionComponent = observer(() => { export const SelectProjectScreen: React.FunctionComponent = observer(() => {
const [selectProjectStore] = React.useState( const [selectProjectStore] = React.useState(
() => new SelectProjectStore(new SelectProjectRepository()) () => new SelectProjectStore(new SelectProjectRepository())
); );
const navigate = useNavigate();
return ( return (
<> <>
@ -25,7 +27,13 @@ export const SelectProjectScreen: React.FunctionComponent = observer(() => {
return ( return (
<> <>
<div>{el.description}</div> <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 { SelectProjectRepository } from "../data/select_project_repository";
import { IProjectModel } from "../model/project_model"; import { IProjectModel } from "../model/project_model";
import { BaseStore } from "../../../core/store/base_store";
export class SelectProjectStore { export class SelectProjectStore extends BaseStore {
repository: SelectProjectRepository; repository: SelectProjectRepository;
isLoading = false;
isError = false;
page = 1; page = 1;
projects: IProjectModel[] = []; projects: IProjectModel[] = [];
constructor(repository: SelectProjectRepository) { constructor(repository: SelectProjectRepository) {
super()
this.repository = repository; this.repository = repository;
makeAutoObservable(this); makeAutoObservable(this);
this.getPipelines(); this.getPipelines();

View file

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

View file

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