Merge branch 'develop' into jyjeun_develop

This commit is contained in:
jaeyeouljeon
2022-09-28 18:26:40 +09:00
22 changed files with 557 additions and 344 deletions

View File

@@ -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')

View File

@@ -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[]> {

View File

@@ -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);

View File

@@ -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`;
}
}

View File

@@ -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;
}

View File

@@ -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: {

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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";

View File

@@ -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;
}

View File

@@ -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'})

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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",

View File

@@ -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",

View 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;

View File

@@ -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>,
);

View File

@@ -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;

View File

@@ -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);
};

View File

@@ -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 => {

View File

@@ -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);