Merge branch 'develop' into jyjeun_develop
This commit is contained in:
@@ -28,13 +28,20 @@ export class DatabaseController {
|
||||
}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.databaseService.findAll();
|
||||
async findAll() {
|
||||
const resultList = await this.databaseService.findAll();
|
||||
|
||||
resultList.forEach(db => {
|
||||
db.knexConfig = JSON.parse(db.knexConfig);
|
||||
});
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.databaseService.findOne(+id);
|
||||
async findOne(@Param('id') id: string) {
|
||||
const resultDB = await this.databaseService.findOne(+id);
|
||||
resultDB.knexConfig = JSON.parse(resultDB.knexConfig);
|
||||
return resultDB;
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
|
||||
@@ -14,8 +14,9 @@ export class DatabaseService {
|
||||
}
|
||||
|
||||
async create(createDatabaseDto: CreateDatabaseDto): Promise<Database> {
|
||||
const database = Database.toDto(createDatabaseDto);
|
||||
return await this.databaseRepository.save(database);
|
||||
const databaseDto = Database.toDto(createDatabaseDto);
|
||||
databaseDto.knexConfig = JSON.stringify(databaseDto.knexConfig);
|
||||
return await this.databaseRepository.save(databaseDto);
|
||||
}
|
||||
|
||||
async findAll(): Promise<Database[]> {
|
||||
|
||||
@@ -7,6 +7,10 @@ import { UpdateDatasetDto } from './dto/update-dataset.dto';
|
||||
export class DatasetController {
|
||||
constructor(private readonly datasetService: DatasetService) {}
|
||||
|
||||
/**
|
||||
* 데이터셋 생성
|
||||
* @param createDatasetDto
|
||||
*/
|
||||
@Post()
|
||||
create(@Body() createDatasetDto: CreateDatasetDto) {
|
||||
return this.datasetService.create(createDatasetDto);
|
||||
|
||||
@@ -1,26 +1,39 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CreateDatasetDto } from './dto/create-dataset.dto';
|
||||
import { UpdateDatasetDto } from './dto/update-dataset.dto';
|
||||
import {Injectable} from '@nestjs/common';
|
||||
import {CreateDatasetDto} from './dto/create-dataset.dto';
|
||||
import {UpdateDatasetDto} from './dto/update-dataset.dto';
|
||||
import {InjectRepository} from "@nestjs/typeorm";
|
||||
import {Repository} from "typeorm";
|
||||
import {Dataset} from "@google-cloud/bigquery";
|
||||
|
||||
@Injectable()
|
||||
export class DatasetService {
|
||||
create(createDatasetDto: CreateDatasetDto) {
|
||||
return 'This action adds a new dataset';
|
||||
}
|
||||
constructor(
|
||||
@InjectRepository(Dataset)
|
||||
private readonly datasetRepository: Repository<Dataset>
|
||||
) {
|
||||
}
|
||||
|
||||
findAll() {
|
||||
return `This action returns all dataset`;
|
||||
}
|
||||
/**
|
||||
* 데이터셋 추가
|
||||
* @param createDatasetDto
|
||||
*/
|
||||
async create(createDatasetDto: CreateDatasetDto) {
|
||||
return await this.datasetRepository.save(createDatasetDto);
|
||||
}
|
||||
|
||||
findOne(id: number) {
|
||||
return `This action returns a #${id} dataset`;
|
||||
}
|
||||
findAll() {
|
||||
return `This action returns all dataset`;
|
||||
}
|
||||
|
||||
update(id: number, updateDatasetDto: UpdateDatasetDto) {
|
||||
return `This action updates a #${id} dataset`;
|
||||
}
|
||||
findOne(id: number) {
|
||||
return `This action returns a #${id} dataset`;
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
return `This action removes a #${id} dataset`;
|
||||
}
|
||||
update(id: number, updateDatasetDto: UpdateDatasetDto) {
|
||||
return `This action updates a #${id} dataset`;
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
return `This action removes a #${id} dataset`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
export class CreateDatasetDto {}
|
||||
import {IsNumber, IsString} from "class-validator";
|
||||
|
||||
export class CreateDatasetDto {
|
||||
@IsString()
|
||||
readonly title: string;
|
||||
|
||||
@IsNumber()
|
||||
readonly databaseId: number;
|
||||
|
||||
@IsString()
|
||||
readonly query:string;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ExpressAdapter } from '@nestjs/platform-express';
|
||||
import { HttpExceptionFilter } from './nest-utils/http-exception.filter';
|
||||
|
||||
async function bootstrap() {
|
||||
const expressApp = express();
|
||||
const expressApp = express();
|
||||
const app = await NestFactory.create(AppModule, new ExpressAdapter(expressApp), {
|
||||
logger: console,
|
||||
cors: {
|
||||
|
||||
@@ -1,88 +1,87 @@
|
||||
import {Body, Controller, Delete, Get, HttpStatus, Param, Post, Put, Res} from '@nestjs/common';
|
||||
import {TemplateService} from './template.service';
|
||||
import {CreateTemplateDto} from './dto/create-template.dto';
|
||||
import {UpdateTemplateDto} from './dto/update-template.dto';
|
||||
import {CreateTemplateItemDto} from "./dto/create-template-item.dto";
|
||||
import {UpdateTemplateItemDto} from "./dto/update-template-item.dto";
|
||||
import {TemplateInfoDto} from "./dto/template-info.dto";
|
||||
import { Body, Controller, Delete, Get, HttpStatus, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { TemplateService } from './template.service';
|
||||
import { CreateTemplateDto } from './dto/create-template.dto';
|
||||
import { UpdateTemplateDto } from './dto/update-template.dto';
|
||||
import { CreateTemplateItemDto } from './dto/create-template-item.dto';
|
||||
import { UpdateTemplateItemDto } from './dto/update-template-item.dto';
|
||||
import { TemplateInfoDto } from './dto/template-info.dto';
|
||||
|
||||
@Controller('template')
|
||||
export class TemplateController {
|
||||
constructor(private readonly templateService: TemplateService) {
|
||||
}
|
||||
constructor(private readonly templateService: TemplateService) {}
|
||||
|
||||
/**
|
||||
* 템플릿 생성
|
||||
* @param createTemplateDto
|
||||
*/
|
||||
@Post()
|
||||
create(@Body() createTemplateDto: CreateTemplateDto) {
|
||||
return this.templateService.create(createTemplateDto);
|
||||
}
|
||||
/**
|
||||
* 템플릿 생성
|
||||
* @param createTemplateDto
|
||||
*/
|
||||
@Post()
|
||||
create(@Body() createTemplateDto: CreateTemplateDto) {
|
||||
return this.templateService.create(createTemplateDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 아이템 생성
|
||||
* @param createTemplateItemDto
|
||||
*/
|
||||
@Post('/item')
|
||||
createItem(@Body() createTemplateItemDto: CreateTemplateItemDto) {
|
||||
return this.templateService.createItem(createTemplateItemDto);
|
||||
}
|
||||
/**
|
||||
* 템플릿 상세 아이템 생성
|
||||
* @param createTemplateItemDto
|
||||
*/
|
||||
@Post('/item')
|
||||
createItem(@Body() createTemplateItemDto: CreateTemplateItemDto) {
|
||||
return this.templateService.createItem(createTemplateItemDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 목록 조회
|
||||
*/
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.templateService.findAll();
|
||||
}
|
||||
/**
|
||||
* 템플릿 목록 조회
|
||||
*/
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.templateService.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 단건 조회
|
||||
* @param id
|
||||
*/
|
||||
@Get(':id')
|
||||
async findOne(@Res() res, @Param('id') id: number) {
|
||||
const resultTemplate: TemplateInfoDto = await this.templateService.findOne(id);
|
||||
return res.status(HttpStatus.OK).json(resultTemplate);
|
||||
}
|
||||
/**
|
||||
* 템플릿 단건 조회
|
||||
* @param id
|
||||
*/
|
||||
@Get(':id')
|
||||
async findOne(@Res() res, @Param('id') id: number) {
|
||||
const resultTemplate: TemplateInfoDto = await this.templateService.findOne(id);
|
||||
return res.status(HttpStatus.OK).json(resultTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 단건 업데이트
|
||||
* @param id
|
||||
* @param updateTemplateDto
|
||||
*/
|
||||
@Put(':id')
|
||||
update(@Param('id') id: string, @Body() updateTemplateDto: UpdateTemplateDto) {
|
||||
return this.templateService.update(+id, updateTemplateDto);
|
||||
}
|
||||
/**
|
||||
* 템플릿 단건 업데이트
|
||||
* @param id
|
||||
* @param updateTemplateDto
|
||||
*/
|
||||
@Put(':id')
|
||||
update(@Param('id') id: string, @Body() updateTemplateDto: UpdateTemplateDto) {
|
||||
return this.templateService.update(+id, updateTemplateDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 아이템 단건 업데이트
|
||||
* @param id
|
||||
* @param updateTemplateDto
|
||||
*/
|
||||
@Put('/item/:id')
|
||||
updateItem(@Param('id') id: string, @Body() updateTemplateItemDto: UpdateTemplateItemDto) {
|
||||
return this.templateService.updateItem(+id, updateTemplateItemDto);
|
||||
}
|
||||
/**
|
||||
* 템플릿 상세 아이템 단건 업데이트
|
||||
* @param id
|
||||
* @param updateTemplateDto
|
||||
*/
|
||||
@Put('/item/:id')
|
||||
updateItem(@Param('id') id: string, @Body() updateTemplateItemDto: UpdateTemplateItemDto) {
|
||||
return this.templateService.updateItem(+id, updateTemplateItemDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 삭제 (사용여부 N 처리)
|
||||
* @param id
|
||||
*/
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.templateService.remove(+id);
|
||||
}
|
||||
/**
|
||||
* 템플릿 삭제 (사용여부 N 처리)
|
||||
* @param id
|
||||
*/
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.templateService.remove(+id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 추천 목록 조회
|
||||
* @param widgets
|
||||
*/
|
||||
//todo:: yhs:: 추천 알고리즘 적용해서 조회해 와야함
|
||||
@Post('/recommend')
|
||||
findRecommendAll(@Body() widgets: any[]) {
|
||||
return this.templateService.findRecommendTemplates(widgets);
|
||||
}
|
||||
/**
|
||||
* 템플릿 추천 목록 조회
|
||||
* @param widgets
|
||||
*/
|
||||
//todo:: yhs:: 추천 알고리즘 적용해서 조회해 와야함
|
||||
@Post('/recommend')
|
||||
findRecommendAll(@Body() widgets: number[]) {
|
||||
return this.templateService.findRecommendTemplates(widgets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,191 +1,208 @@
|
||||
import {Injectable} from '@nestjs/common';
|
||||
import {CreateTemplateDto} from './dto/create-template.dto';
|
||||
import {UpdateTemplateDto} from './dto/update-template.dto';
|
||||
import {InjectRepository} from "@nestjs/typeorm";
|
||||
import {Template} from "./entities/template.entity";
|
||||
import {Repository} from "typeorm";
|
||||
import {YesNo} from "../common/enum/yn.enum";
|
||||
import {TemplateItem} from "./entities/template-item.entity";
|
||||
import {CreateTemplateItemDto} from "./dto/create-template-item.dto";
|
||||
import {UpdateTemplateItemDto} from "./dto/update-template-item.dto";
|
||||
import {TemplateInfoDto} from "./dto/template-info.dto";
|
||||
import {ItemInfoDto} from "./dto/item-info.dto";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CreateTemplateDto } from './dto/create-template.dto';
|
||||
import { UpdateTemplateDto } from './dto/update-template.dto';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Template } from './entities/template.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
import { YesNo } from '../common/enum/yn.enum';
|
||||
import { TemplateItem } from './entities/template-item.entity';
|
||||
import { CreateTemplateItemDto } from './dto/create-template-item.dto';
|
||||
import { UpdateTemplateItemDto } from './dto/update-template-item.dto';
|
||||
import { TemplateInfoDto } from './dto/template-info.dto';
|
||||
import { ItemInfoDto } from './dto/item-info.dto';
|
||||
|
||||
@Injectable()
|
||||
export class TemplateService {
|
||||
constructor(
|
||||
@InjectRepository(Template)
|
||||
private readonly templateRepository: Repository<Template>,
|
||||
@InjectRepository(TemplateItem)
|
||||
private readonly templateItemRepository: Repository<TemplateItem>
|
||||
) {
|
||||
constructor(
|
||||
@InjectRepository(Template)
|
||||
private readonly templateRepository: Repository<Template>,
|
||||
@InjectRepository(TemplateItem)
|
||||
private readonly templateItemRepository: Repository<TemplateItem>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 템플릿 추가
|
||||
* @param createTemplate
|
||||
*/
|
||||
async create(createTemplate: CreateTemplateDto): Promise<Template> {
|
||||
const insertItem = await this.templateRepository.save({
|
||||
title: createTemplate.title,
|
||||
description: createTemplate.description,
|
||||
});
|
||||
return insertItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 아이템 추가
|
||||
* @param createTemplateItem
|
||||
*/
|
||||
async createItem(createTemplateItem: CreateTemplateItemDto): Promise<TemplateItem> {
|
||||
const insertItem = await this.templateItemRepository.save({
|
||||
templateId: createTemplateItem.templateId,
|
||||
x: createTemplateItem.x,
|
||||
y: createTemplateItem.y,
|
||||
width: createTemplateItem.width,
|
||||
height: createTemplateItem.height,
|
||||
recommendCategory: createTemplateItem.recommendCategory,
|
||||
});
|
||||
return insertItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 목록 조회
|
||||
*/
|
||||
async findAll() {
|
||||
const result = await this.templateRepository.find({
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
},
|
||||
where: {
|
||||
useYn: YesNo.YES,
|
||||
},
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 단건 조회
|
||||
* @param id
|
||||
*/
|
||||
async findOne(id: number): Promise<TemplateInfoDto> {
|
||||
let returnObj: TemplateInfoDto;
|
||||
|
||||
// 템플릿 기본 정보 조회
|
||||
const templateInfo = await this.templateRepository.findOne({
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
},
|
||||
where: {
|
||||
useYn: YesNo.YES,
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (templateInfo.id) {
|
||||
returnObj = new TemplateInfoDto(templateInfo);
|
||||
// 템플릿 상세 아이템 조회(layout 조회 및 가공)
|
||||
const layoutList = await this.templateItemRepository.find({
|
||||
where: {
|
||||
templateId: templateInfo.id,
|
||||
},
|
||||
});
|
||||
const layout = [];
|
||||
layoutList.map(item => {
|
||||
const itemInfo: ItemInfoDto = new ItemInfoDto(item);
|
||||
layout.push(itemInfo);
|
||||
});
|
||||
returnObj.layout = layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 추가
|
||||
* @param createTemplate
|
||||
*/
|
||||
async create(createTemplate: CreateTemplateDto): Promise<Template> {
|
||||
const insertItem = await this.templateRepository.save({
|
||||
title: createTemplate.title,
|
||||
description: createTemplate.description,
|
||||
return returnObj;
|
||||
}
|
||||
|
||||
})
|
||||
return insertItem;
|
||||
/**
|
||||
* 템플릿 업데이트
|
||||
* @param id
|
||||
* @param updateTemplateDto
|
||||
*/
|
||||
async update(id: number, updateTemplateDto: UpdateTemplateDto) {
|
||||
const updateItem = await this.templateRepository.update(
|
||||
{
|
||||
id: id,
|
||||
},
|
||||
{
|
||||
title: updateTemplateDto.title,
|
||||
description: updateTemplateDto.description,
|
||||
},
|
||||
);
|
||||
|
||||
let msg = `This action updates a #${id} template`;
|
||||
if (updateItem.affected < 1) {
|
||||
msg = '변동사항 없음';
|
||||
} else if (updateItem.affected > 1) {
|
||||
msg = '여러개 바뀜';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 아이템 추가
|
||||
* @param createTemplateItem
|
||||
*/
|
||||
async createItem(createTemplateItem: CreateTemplateItemDto): Promise<TemplateItem> {
|
||||
const insertItem = await this.templateItemRepository.save({
|
||||
templateId: createTemplateItem.templateId,
|
||||
x: createTemplateItem.x,
|
||||
y: createTemplateItem.y,
|
||||
width: createTemplateItem.width,
|
||||
height: createTemplateItem.height,
|
||||
recommendCategory: createTemplateItem.recommendCategory,
|
||||
})
|
||||
return insertItem;
|
||||
/**
|
||||
* 템플릿 상세 아이템 수정
|
||||
* @param id
|
||||
* @param updateTemplateItem
|
||||
*/
|
||||
async updateItem(id: number, updateTemplateItem: UpdateTemplateItemDto) {
|
||||
const updateItem = await this.templateItemRepository.update(
|
||||
{
|
||||
id: id,
|
||||
},
|
||||
{
|
||||
x: updateTemplateItem.x,
|
||||
y: updateTemplateItem.y,
|
||||
width: updateTemplateItem.width,
|
||||
height: updateTemplateItem.height,
|
||||
recommendCategory: updateTemplateItem.recommendCategory,
|
||||
},
|
||||
);
|
||||
|
||||
let msg = `This action updates a #${id} templateItem`;
|
||||
if (updateItem.affected < 1) {
|
||||
msg = '변동사항 없음';
|
||||
} else if (updateItem.affected > 1) {
|
||||
msg = '여러개 바뀜';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 목록 조회
|
||||
*/
|
||||
async findAll() {
|
||||
const result = await this.templateRepository.find({
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
},
|
||||
where: {
|
||||
useYn: YesNo.YES
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 템플릿 비활성화(useYn='N')
|
||||
* @param id
|
||||
*/
|
||||
async remove(id: number) {
|
||||
const deleteItem = await this.templateRepository.update(
|
||||
{
|
||||
id: id,
|
||||
},
|
||||
{
|
||||
useYn: YesNo.NO,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
let msg = `#${id} template useYn='N' 변경완료 `;
|
||||
if (deleteItem.affected < 1) {
|
||||
msg = '변동사항 없음';
|
||||
} else if (deleteItem.affected > 1) {
|
||||
msg = '여러개 바뀜';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 단건 조회
|
||||
* @param id
|
||||
*/
|
||||
async findOne(id: number): Promise<TemplateInfoDto> {
|
||||
let returnObj: TemplateInfoDto;
|
||||
/**
|
||||
* 선택된 위젯목록으로 추천될 template 목록
|
||||
* @param widgets
|
||||
*/
|
||||
async findRecommendTemplates(widgets: number[]) {
|
||||
const returnArr = [];
|
||||
const tempTemplateInfo = new TemplateItem();
|
||||
returnArr.push(tempTemplateInfo);
|
||||
|
||||
// 템플릿 기본 정보 조회
|
||||
const templateInfo = await this.templateRepository.findOne({
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
},
|
||||
where: {
|
||||
useYn: YesNo.YES,
|
||||
id: id,
|
||||
}
|
||||
});
|
||||
const templateList = await this.templateRepository.find({
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
},
|
||||
where: {
|
||||
useYn: YesNo.YES,
|
||||
},
|
||||
});
|
||||
|
||||
if(templateInfo.id){
|
||||
returnObj = new TemplateInfoDto(templateInfo);
|
||||
// 템플릿 상세 아이템 조회(layout 조회 및 가공)
|
||||
const layoutList = await this.templateItemRepository.find({
|
||||
where: {
|
||||
templateId: templateInfo.id
|
||||
}
|
||||
});
|
||||
const layout = [];
|
||||
layoutList.map((item) => {
|
||||
const itemInfo:ItemInfoDto = new ItemInfoDto(item);
|
||||
layout.push(itemInfo);
|
||||
})
|
||||
returnObj.layout = layout;
|
||||
}
|
||||
// return result;
|
||||
|
||||
return returnObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 업데이트
|
||||
* @param id
|
||||
* @param updateTemplateDto
|
||||
*/
|
||||
async update(id: number, updateTemplateDto: UpdateTemplateDto) {
|
||||
|
||||
const updateItem = await this.templateRepository.update({
|
||||
id: id
|
||||
}, {
|
||||
title: updateTemplateDto.title,
|
||||
description: updateTemplateDto.description,
|
||||
});
|
||||
|
||||
let msg = `This action updates a #${id} template`
|
||||
if (updateItem.affected < 1) {
|
||||
msg = '변동사항 없음';
|
||||
} else if (updateItem.affected > 1) {
|
||||
msg = '여러개 바뀜';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 아이템 수정
|
||||
* @param id
|
||||
* @param updateTemplateItem
|
||||
*/
|
||||
async updateItem(id: number,updateTemplateItem: UpdateTemplateItemDto) {
|
||||
const updateItem = await this.templateItemRepository.update({
|
||||
id: id
|
||||
}, {
|
||||
x: updateTemplateItem.x,
|
||||
y: updateTemplateItem.y,
|
||||
width: updateTemplateItem.width,
|
||||
height: updateTemplateItem.height,
|
||||
recommendCategory: updateTemplateItem.recommendCategory
|
||||
});
|
||||
|
||||
let msg = `This action updates a #${id} templateItem`
|
||||
if (updateItem.affected < 1) {
|
||||
msg = '변동사항 없음';
|
||||
} else if (updateItem.affected > 1) {
|
||||
msg = '여러개 바뀜';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 비활성화(useYn='Y')
|
||||
* @param id
|
||||
*/
|
||||
async remove(id: number) {
|
||||
const deleteItem = await this.templateRepository.update({
|
||||
id: id
|
||||
}, {
|
||||
useYn: YesNo.YES
|
||||
});
|
||||
|
||||
let msg = `#${id} template useYn='Y' 변경완료 `
|
||||
if (deleteItem.affected < 1) {
|
||||
msg = '변동사항 없음';
|
||||
} else if (deleteItem.affected > 1) {
|
||||
msg = '여러개 바뀜';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 선택된 위젯목록으로 추천될 template 목록
|
||||
* @param widgets
|
||||
*/
|
||||
async findRecommendTemplates(widgets: any[]): Promise<TemplateInfoDto[]> {
|
||||
const returnArr = [];
|
||||
const tempTemplateInfo = new TemplateItem();
|
||||
returnArr.push(tempTemplateInfo);
|
||||
|
||||
|
||||
|
||||
return returnArr;
|
||||
}
|
||||
return templateList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {Column, Entity, JoinTable, ManyToMany, OneToMany, PrimaryGeneratedColumn} from "typeorm";
|
||||
import {Database} from "../../database/entities/database.entity";
|
||||
import {Column, Entity, OneToMany, PrimaryGeneratedColumn} from "typeorm";
|
||||
import {BaseEntity} from "../../common/entities/base.entity";
|
||||
import {Widget} from "../../widget/entities/widget.entity";
|
||||
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
import {IsNotEmpty, IsNumber, IsString} from "class-validator";
|
||||
import {DatasetType} from "../../common/enum/dataset-type.enum";
|
||||
import {YesNo} from "../../common/enum/yn.enum";
|
||||
import { IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator';
|
||||
import { DatasetType } from '../../common/enum/dataset-type.enum';
|
||||
import { YesNo } from '../../common/enum/yn.enum';
|
||||
|
||||
export class CreateWidgetDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
title: string;
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
title: string;
|
||||
|
||||
@IsString()
|
||||
description: string;
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description: string;
|
||||
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
componentId: number;
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
componentId: number;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
datasetType: DatasetType
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
datasetType: DatasetType;
|
||||
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
datasetId: number
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
datasetId: number;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
option: string
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
tableName: string;
|
||||
|
||||
@IsString()
|
||||
delYn: YesNo
|
||||
|
||||
@IsNumber()
|
||||
widgetViewId: number
|
||||
}
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
option: string;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export class Widget extends BaseEntity {
|
||||
@Column({comment: '컴포넌트 ID'})
|
||||
componentId: number
|
||||
|
||||
@Column({comment: '데이터셋 구분(데이터셋, 위젯 데이터셋)', default: DatasetType.WIDGET})
|
||||
@Column({comment: '데이터셋 구분(데이터셋, 위젯 뷰)', default: DatasetType.WIDGET})
|
||||
datasetType: DatasetType
|
||||
|
||||
@Column({comment: '데이터셋 ID'})
|
||||
|
||||
@@ -7,11 +7,18 @@ import { UpdateWidgetDto } from './dto/update-widget.dto';
|
||||
export class WidgetController {
|
||||
constructor(private readonly widgetService: WidgetService) {}
|
||||
|
||||
/**
|
||||
* 위젯 생성
|
||||
* @param createWidgetDto
|
||||
*/
|
||||
@Post()
|
||||
create(@Body() createWidgetDto: CreateWidgetDto) {
|
||||
return this.widgetService.create(createWidgetDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 위젯 목록 조회
|
||||
*/
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.widgetService.findAll();
|
||||
|
||||
@@ -1,65 +1,78 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { CreateWidgetDto } from './dto/create-widget.dto';
|
||||
import { UpdateWidgetDto } from './dto/update-widget.dto';
|
||||
import { Repository } from "typeorm";
|
||||
import { Widget } from "./entities/widget.entity";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from 'typeorm';
|
||||
import { Widget } from './entities/widget.entity';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DatasetType } from '../common/enum/dataset-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class WidgetService {
|
||||
constructor(
|
||||
@InjectRepository(Widget)
|
||||
private widgetRepository: Repository<Widget>) {}
|
||||
@InjectRepository(Widget)
|
||||
private widgetRepository: Repository<Widget>,
|
||||
) {}
|
||||
|
||||
async create(body: CreateWidgetDto) {
|
||||
async create(createWidgetDto: CreateWidgetDto) {
|
||||
// const find_widget = await this.widgetRepository.findOne({where: { title: createWidgetDto.title }})
|
||||
// if(find_widget){
|
||||
// return 'exist same widget'
|
||||
// } else {
|
||||
// await this.widgetRepository.save({
|
||||
// title: body.title,
|
||||
// description: body.description,
|
||||
// componentId: body.componentId,
|
||||
// datasetType: body.datasetType,
|
||||
// datasetId: body.datasetId,
|
||||
// option: JSON.stringify(body.option),
|
||||
// delYn: body.delYn
|
||||
// })
|
||||
// }
|
||||
|
||||
const find_widget = await this.widgetRepository.findOne({where: { title: body.title }})
|
||||
if(find_widget){
|
||||
return 'exist same widget'
|
||||
} else {
|
||||
// await this.widgetRepository.save({
|
||||
// title: body.title,
|
||||
// description: body.description,
|
||||
// componentId: body.componentId,
|
||||
// datasetType: body.datasetType,
|
||||
// datasetId: body.datasetId,
|
||||
// option: JSON.stringify(body.option),
|
||||
// delYn: body.delYn
|
||||
// })
|
||||
if (
|
||||
createWidgetDto.datasetType === DatasetType.WIDGET &&
|
||||
createWidgetDto.tableName.length <= 0
|
||||
) {
|
||||
throw new BadRequestException('테이블명이 존재하지 않습니다.');
|
||||
} else if (createWidgetDto.datasetType === DatasetType.DATASET && !createWidgetDto.datasetId) {
|
||||
throw new BadRequestException('datasetId가 존재하지 않아');
|
||||
}
|
||||
|
||||
// todo:: 테이블 선택해서 생성할 경우(DatasetType : WIDGET), 위젯 뷰 아이템을 추가하고 추가된 id값을 넣어줘야 한다.
|
||||
// todo:: 데이터셋 선택해서 생성할 경우 그대로 insert(DatasetType : DATASET)
|
||||
|
||||
createWidgetDto.option = JSON.stringify(createWidgetDto.option);
|
||||
|
||||
return 'This action adds a new widget';
|
||||
}
|
||||
|
||||
async findAll() {
|
||||
const find_all = await this.widgetRepository.find()
|
||||
return find_all
|
||||
const find_all = await this.widgetRepository.find();
|
||||
return find_all;
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
|
||||
const find_widget = await this.widgetRepository.findOne({ where: { id: id }})
|
||||
const find_widget = await this.widgetRepository.findOne({ where: { id: id } });
|
||||
return find_widget;
|
||||
}
|
||||
|
||||
async update(id: number, body: UpdateWidgetDto) {
|
||||
const find_widget = await this.widgetRepository.findOne({ where: { id: id}})
|
||||
if(!find_widget){
|
||||
return 'No exist widget'
|
||||
const find_widget = await this.widgetRepository.findOne({ where: { id: id } });
|
||||
if (!find_widget) {
|
||||
return 'No exist widget';
|
||||
} else {
|
||||
|
||||
find_widget.title = body.title;
|
||||
find_widget.componentId = body.componentId;
|
||||
find_widget.datasetType = body.datasetType;
|
||||
find_widget.datasetId = body.datasetId;
|
||||
find_widget.option = JSON.stringify(body.option);
|
||||
find_widget.delYn = body.delYn;
|
||||
find_widget.widgetViewId = body.widgetViewId;
|
||||
// find_widget.delYn = body.delYn;
|
||||
// find_widget.widgetViewId = body.widgetViewId;
|
||||
|
||||
await this.widgetRepository.save(find_widget)
|
||||
await this.widgetRepository.save(find_widget);
|
||||
|
||||
return `This action updates a #${id} widget`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
|
||||
9
frontend-web/package-lock.json
generated
9
frontend-web/package-lock.json
generated
@@ -20044,6 +20044,15 @@
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"react-alert": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-alert/-/react-alert-7.0.3.tgz",
|
||||
"integrity": "sha512-cZ2ZhxytECTxljDfBKpQmwWbfJQFzFf2Qf03L/IB5shbEXtWhDD2JjiW60rwmKT1oZoU+GEnUQw5MFM5+f0B6A==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2",
|
||||
"react-transition-group": "^4.4.1"
|
||||
}
|
||||
},
|
||||
"react-app-polyfill": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-alert": "^7.0.3",
|
||||
"react-color": "^2.19.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
|
||||
88
frontend-web/src/components/alert/index.tsx
Normal file
88
frontend-web/src/components/alert/index.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import React from 'react';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import Button from '@mui/material/Button';
|
||||
import { Divider } from '@mui/material';
|
||||
|
||||
interface IProps {
|
||||
message: string | JSX.Element;
|
||||
options: {
|
||||
title?: string | JSX.Element;
|
||||
actions?: {
|
||||
copy: string;
|
||||
onClick: any;
|
||||
}[];
|
||||
closeCopy?: string;
|
||||
};
|
||||
close: any;
|
||||
}
|
||||
|
||||
const buttonStyle = { minWidth: 80, height: 36, padding: '0 10px', fontSize: '13px', fontWeight: 'bold' };
|
||||
|
||||
const AlertDialog = ({ close, message, options }: IProps) => {
|
||||
const hasTitle = options.title && options.title.toString().trim() !== '';
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
onClose={close}
|
||||
keepMounted
|
||||
aria-labelledby="alert-dialog-slide-title"
|
||||
aria-describedby="alert-dialog-slide-description"
|
||||
PaperProps={{
|
||||
sx: {
|
||||
borderRadius: '4px',
|
||||
minWidth: { xs: 'calc(100vw - 32px)', sm: 0 },
|
||||
},
|
||||
}}
|
||||
BackdropProps={{ style: { background: 'rgba(31, 33, 35, 0.85)' } }}
|
||||
>
|
||||
<DialogTitle sx={{ padding: '16px 20px', fontSize: '14px', fontWeight: 'bold', lineHeight: 'normal' }}>
|
||||
{options.title}
|
||||
</DialogTitle>
|
||||
{hasTitle ? <Divider sx={{ backgroundColor: '#1f2123', opacity: 0.1 }} /> : null}
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText
|
||||
id="alert-dialog-slide-description"
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
color: 'black',
|
||||
paddingTop: hasTitle ? 0 : '20px',
|
||||
minWidth: 300,
|
||||
maxWidth: 500,
|
||||
whiteSpace: 'pre-wrap',
|
||||
textAlign: 'center',
|
||||
lineHeight: '24px',
|
||||
}}
|
||||
>
|
||||
{message}
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ margin: '24px', padding: 0, justifyContent: 'center' }}>
|
||||
{options.actions &&
|
||||
options.actions.map((action, index) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
action.onClick();
|
||||
close();
|
||||
}}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
sx={buttonStyle}
|
||||
key={index}
|
||||
>
|
||||
{action.copy}
|
||||
</Button>
|
||||
))}
|
||||
<Button variant="contained" color="secondary" sx={buttonStyle} onClick={close}>
|
||||
{options.closeCopy || '확인'}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default AlertDialog;
|
||||
@@ -2,16 +2,29 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { ThemeProvider } from '@mui/material/styles';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { positions, Provider as AlertProvider, transitions } from 'react-alert';
|
||||
import AlertTemplate from './components/alert';
|
||||
|
||||
import theme from './theme/theme';
|
||||
import App from './App';
|
||||
import './index.css';
|
||||
|
||||
// alert optional configuration
|
||||
const options = {
|
||||
// you can also just use 'bottom center'
|
||||
position: positions.BOTTOM_CENTER,
|
||||
offset: '30px',
|
||||
// you can also just use 'scale'
|
||||
transition: transitions.SCALE,
|
||||
};
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<BrowserRouter>
|
||||
<ThemeProvider theme={theme}>
|
||||
<App />
|
||||
<AlertProvider template={AlertTemplate} {...options}>
|
||||
<App />
|
||||
</AlertProvider>
|
||||
</ThemeProvider>
|
||||
</BrowserRouter>,
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Stack } from '@mui/material';
|
||||
import DataGrid from '@/components/DataGrid';
|
||||
import DataGrid from '@/components/dataGrid';
|
||||
|
||||
const TableBoard = props => {
|
||||
const { option, dataSet } = props;
|
||||
|
||||
@@ -7,6 +7,7 @@ import AddWidgetPopup from '@/pages/Dashboard/Components/AddWidgetPopup';
|
||||
import ConfirmCancelButton, { ConfirmButton, CancelButton } from '@/components/button/ConfirmCancelButton';
|
||||
import DialogAlertButton from '@/components/button/DialogAlertButton';
|
||||
import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout';
|
||||
import { useAlert } from 'react-alert';
|
||||
|
||||
import '/node_modules/react-grid-layout/css/styles.css';
|
||||
import '/node_modules/react-resizable/css/styles.css';
|
||||
@@ -19,6 +20,7 @@ import DashboardService from '@/api/dashboardService';
|
||||
const ResponsiveGridLayout = WidthProvider(Responsive);
|
||||
|
||||
function DashboardModify() {
|
||||
const alert = useAlert();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const [dashboardId, setDashboardId] = useState(null); // dashboard id
|
||||
@@ -148,7 +150,11 @@ function DashboardModify() {
|
||||
// title null 체크, widgets 수 체크 (0개면 저장 못함)
|
||||
if (dashboardTitle == null || dashboardTitle.trim() == '') {
|
||||
// title 이 없을 경우
|
||||
alert('제목을 입력하세요');
|
||||
alert.info('제목을 입력 해주세요.', {
|
||||
onClose: () => {
|
||||
console.log('test alert');
|
||||
},
|
||||
});
|
||||
} else if (layout.length == 0 || widgets.length == 0) {
|
||||
// 배치된 widget 이 없을경우
|
||||
alert('배치된 위젯이 없습니다');
|
||||
@@ -175,6 +181,11 @@ function DashboardModify() {
|
||||
};
|
||||
|
||||
const handleWidgetOpen = () => {
|
||||
alert.info('위젯을 선택', {
|
||||
onClose: () => {
|
||||
console.log('test alert');
|
||||
},
|
||||
});
|
||||
setWidgetOpen(true);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'ace-builds/src-noconflict/theme-tomorrow';
|
||||
import 'ace-builds/src-noconflict/snippets/mysql';
|
||||
import 'ace-builds/src-min-noconflict/ext-language_tools';
|
||||
import { get, post } from '@/helpers/apiHelper';
|
||||
import DataGrid from '@/components/DataGrid';
|
||||
import DataGrid from '@/components/dataGrid';
|
||||
import { OptColumn } from 'tui-grid/types/options';
|
||||
|
||||
const DataSet = props => {
|
||||
|
||||
@@ -20,8 +20,11 @@ import ScatterChartSetting from '@/widget/settings/ScatterChartSetting';
|
||||
import TitleBox from '@/components/TitleBox';
|
||||
import BubbleChart from '@/modules/scatterchart/BubbleChart';
|
||||
import BubbleChartSetting from '@/widget/settings/BubbleChartSetting';
|
||||
import { useAlert } from 'react-alert';
|
||||
|
||||
function WidgetAttributeSelect(props) {
|
||||
const alert = useAlert();
|
||||
|
||||
const { dataSetId, componentType, prevOption } = props;
|
||||
|
||||
const [option, setOption] = useState(null);
|
||||
@@ -254,9 +257,26 @@ function WidgetAttributeSelect(props) {
|
||||
const handleSubmit = event => {
|
||||
event.preventDefault();
|
||||
|
||||
if (option === null) {
|
||||
return;
|
||||
}
|
||||
// alert sample
|
||||
// alert.info('위젯 속성을 저장하시겠습니까?', {
|
||||
// onClose: () => {
|
||||
// console.log('test alert');
|
||||
// },
|
||||
// });
|
||||
|
||||
// confirm sample
|
||||
alert.success('위젯 속성을 저장하시겠습니까?', {
|
||||
title: '위젯 저장',
|
||||
closeCopy: '취소',
|
||||
actions: [
|
||||
{
|
||||
copy: '저장',
|
||||
onClick: () => {
|
||||
console.log('저장클릭');
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
console.log('widgetTitle:', option.title);
|
||||
console.log('datesetId:', dataSetId);
|
||||
|
||||
Reference in New Issue
Block a user