Update keywords
This commit is contained in:
parent
e6a5713c18
commit
d0022eb7d5
|
|
@ -0,0 +1,95 @@
|
||||||
|
import Keyword from '#models/keywords'
|
||||||
|
import type { HttpContext } from '@adonisjs/core/http'
|
||||||
|
|
||||||
|
export default class KeywordsController {
|
||||||
|
/**
|
||||||
|
* Display a list of resource
|
||||||
|
*/
|
||||||
|
async get({}: HttpContext) {
|
||||||
|
const keywords = await Keyword.all()
|
||||||
|
return { status: true, data: keywords }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display form to create a new record
|
||||||
|
*/
|
||||||
|
async create({ auth, request, response }: HttpContext) {
|
||||||
|
let payload = request.only([...Array.from(Keyword.$columnsDefinitions.keys())])
|
||||||
|
try {
|
||||||
|
// Check exist model
|
||||||
|
const existedKeyword = await Keyword.findBy('name', payload.name)
|
||||||
|
if (existedKeyword) {
|
||||||
|
return response.badRequest({
|
||||||
|
status: false,
|
||||||
|
message: 'Keyword already exists',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyword = await Keyword.create({
|
||||||
|
...payload,
|
||||||
|
})
|
||||||
|
return response.created({
|
||||||
|
status: true,
|
||||||
|
message: 'Keyword created successfully',
|
||||||
|
data: keyword,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
return response.badRequest({ error: error, message: 'Keyword create failed', status: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async update({ request, response, auth }: HttpContext) {
|
||||||
|
let payload = request.only(
|
||||||
|
Array.from(Keyword.$columnsDefinitions.keys()).filter(
|
||||||
|
(f) => f !== 'created_at' && f !== 'updated_at'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
const keyword = await Keyword.find(request.body().id)
|
||||||
|
if (!keyword) {
|
||||||
|
return response.status(404).json({ message: 'Keyword not found' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check exist model
|
||||||
|
const existedKeyword = await Keyword.findBy('name', payload.name)
|
||||||
|
if (existedKeyword && existedKeyword.id !== keyword.id) {
|
||||||
|
return response.badRequest({
|
||||||
|
status: false,
|
||||||
|
message: 'Keyword already exists',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(keyword, { ...payload })
|
||||||
|
await keyword.save()
|
||||||
|
return response.ok({ status: true, message: 'Keyword update successfully', data: keyword })
|
||||||
|
} catch (error) {
|
||||||
|
return response.badRequest({ error: error, message: 'Keyword update failed', status: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete record
|
||||||
|
*/
|
||||||
|
async delete({ auth, request, response }: HttpContext) {
|
||||||
|
try {
|
||||||
|
const keyword = await Keyword.find(request.body().id)
|
||||||
|
if (!keyword) {
|
||||||
|
return response.status(404).json({ message: 'Keyword not found' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the keyword
|
||||||
|
await keyword.delete()
|
||||||
|
return response.ok({
|
||||||
|
status: true,
|
||||||
|
message: 'Keyword delete successfully',
|
||||||
|
data: keyword,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
return response.badRequest({
|
||||||
|
error: error,
|
||||||
|
message: 'Keyword delete failed',
|
||||||
|
status: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { DateTime } from 'luxon'
|
||||||
|
import { BaseModel, column } from '@adonisjs/lucid/orm'
|
||||||
|
|
||||||
|
export default class Keyword extends BaseModel {
|
||||||
|
@column({ isPrimary: true })
|
||||||
|
declare id: number
|
||||||
|
|
||||||
|
@column()
|
||||||
|
declare name: string
|
||||||
|
|
||||||
|
@column()
|
||||||
|
declare type: string
|
||||||
|
|
||||||
|
@column()
|
||||||
|
declare match_type: string
|
||||||
|
|
||||||
|
@column()
|
||||||
|
declare is_active: boolean
|
||||||
|
|
||||||
|
@column.dateTime({ autoCreate: true })
|
||||||
|
declare createdAt: DateTime
|
||||||
|
|
||||||
|
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
||||||
|
declare updatedAt: DateTime
|
||||||
|
}
|
||||||
|
|
@ -1614,11 +1614,20 @@ ${log}
|
||||||
<p>Station: <b>${this.config.stationName}</b></p>
|
<p>Station: <b>${this.config.stationName}</b></p>
|
||||||
<p>Line: <b>${this.config.lineNumber}</b></p>
|
<p>Line: <b>${this.config.lineNumber}</b></p>
|
||||||
<p>Model: <b>${pid}</b></p>
|
<p>Model: <b>${pid}</b></p>
|
||||||
<p>RAM: ${mem ? `<b>${mem + ' bytes'} (<span style="color: ${isWarningRAM ? "red" : "black"};">default: ${configRam.ram}</span>)</b>` : ''}</p>
|
<p>RAM: ${mem ? `<b>${mem + ' bytes'} (<span style="color: ${isWarningRAM ? 'red' : 'black'};">default: ${configRam.ram}</span>)</b>` : ''}</p>
|
||||||
<p>FLASH: ${flash ? `<b>${flash + ' bytes'} (<span style="color: ${isWarningFlash ? "red" : "black"};">default: ${configRam.flash}</span>)</b>` : ''}</p>
|
<p>FLASH: ${flash ? `<b>${flash + ' bytes'} (<span style="color: ${isWarningFlash ? 'red' : 'black'};">default: ${configRam.flash}</span>)</b>` : ''}</p>
|
||||||
<hr />
|
<hr />
|
||||||
<div style="white-space: break-spaces; background-color: #f5f5f5; color: black; padding: 8px; max-height: 500px; overflow-y: scroll; border: 1px #ccc solid;"><span style="color: black;">
|
<div style="white-space: break-spaces; background-color: #f5f5f5; color: black; padding: 8px; max-height: 500px; overflow-y: scroll; border: 1px #ccc solid;"><span style="color: black;">
|
||||||
${escapeHtml(output).replace('show ver', '').replace('sh ver', '').replace('show version', '').replace('sh version', '').replace(mem, `<span style="color: ${isWarningRAM ? "red" : "black"};">${mem}</span>`).replace(flash, `<span style="color: ${isWarningFlash ? "red" : "black"};">${flash}</span>`)}</span></div>
|
${escapeHtml(output)
|
||||||
|
.replace('show ver', '')
|
||||||
|
.replace('sh ver', '')
|
||||||
|
.replace('show version', '')
|
||||||
|
.replace('sh version', '')
|
||||||
|
.replace(mem, `<span style="color: ${isWarningRAM ? 'red' : 'black'};">${mem}</span>`)
|
||||||
|
.replace(
|
||||||
|
flash,
|
||||||
|
`<span style="color: ${isWarningFlash ? 'red' : 'black'};">${flash}</span>`
|
||||||
|
)}</span></div>
|
||||||
`
|
`
|
||||||
await sendMessageToMail(subject, body)
|
await sendMessageToMail(subject, body)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,21 +166,21 @@ export function mapToLineFormat(input: InputData) {
|
||||||
const vid = input.inventory?.vid || ''
|
const vid = input.inventory?.vid || ''
|
||||||
const sn = input.inventory?.sn || ''
|
const sn = input.inventory?.sn || ''
|
||||||
|
|
||||||
if (!pid || !sn) {
|
// if (!pid || !sn) {
|
||||||
return {
|
// return {
|
||||||
line,
|
// line,
|
||||||
pid: '',
|
// pid: '',
|
||||||
vid: '',
|
// vid: '',
|
||||||
sn: '',
|
// sn: '',
|
||||||
ios: '',
|
// ios: '',
|
||||||
mac: '',
|
// mac: '',
|
||||||
ram: '',
|
// ram: '',
|
||||||
flash: '',
|
// flash: '',
|
||||||
license: [],
|
// license: [],
|
||||||
issues: ['No data'],
|
// issues: ['No data'],
|
||||||
summary: '',
|
// summary: '',
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// MAC
|
// MAC
|
||||||
let mac = ''
|
let mac = ''
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { BaseSchema } from '@adonisjs/lucid/schema'
|
||||||
|
|
||||||
|
export default class extends BaseSchema {
|
||||||
|
protected tableName = 'keywords'
|
||||||
|
|
||||||
|
async up() {
|
||||||
|
this.schema.createTable(this.tableName, (table) => {
|
||||||
|
table.increments('id')
|
||||||
|
table.string('name').notNullable()
|
||||||
|
table.string('type').notNullable()
|
||||||
|
table.string('match_type').defaultTo('include')
|
||||||
|
table.boolean('is_active').defaultTo(true)
|
||||||
|
table.timestamps()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async down() {
|
||||||
|
this.schema.dropTable(this.tableName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -121,3 +121,12 @@ router
|
||||||
router.post('/delete', '#controllers/config_ram_controller.delete')
|
router.post('/delete', '#controllers/config_ram_controller.delete')
|
||||||
})
|
})
|
||||||
.prefix('/api/config-ram')
|
.prefix('/api/config-ram')
|
||||||
|
|
||||||
|
router
|
||||||
|
.group(() => {
|
||||||
|
router.get('/', '#controllers/keywords_controller.get')
|
||||||
|
router.post('/create', '#controllers/keywords_controller.create')
|
||||||
|
router.post('/update', '#controllers/keywords_controller.update')
|
||||||
|
router.post('/delete', '#controllers/keywords_controller.delete')
|
||||||
|
})
|
||||||
|
.prefix('/api/keywords')
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ import ModalHistory from "./Modal/ModalHistory";
|
||||||
import ModalConfig from "./Modal/ModalConfig";
|
import ModalConfig from "./Modal/ModalConfig";
|
||||||
import DrawerScenario from "./Modal/ModalScenario";
|
import DrawerScenario from "./Modal/ModalScenario";
|
||||||
import ModalConfigRamFlash from "./Modal/ModalConfigRamFlash";
|
import ModalConfigRamFlash from "./Modal/ModalConfigRamFlash";
|
||||||
|
import ModalKeywords from "./Modal/ModalKeywords";
|
||||||
|
|
||||||
interface DraggableTabsProps {
|
interface DraggableTabsProps {
|
||||||
tabsData: TStation[];
|
tabsData: TStation[];
|
||||||
|
|
@ -153,6 +154,7 @@ export default function DraggableTabs({
|
||||||
const [openConfig, setOpenConfig] = useState<boolean>(false);
|
const [openConfig, setOpenConfig] = useState<boolean>(false);
|
||||||
const [openDrawerScenario, setOpenDrawerScenario] = useState<boolean>(false);
|
const [openDrawerScenario, setOpenDrawerScenario] = useState<boolean>(false);
|
||||||
const [openConfigRam, setOpenConfigRam] = useState<boolean>(false);
|
const [openConfigRam, setOpenConfigRam] = useState<boolean>(false);
|
||||||
|
const [openKeywords, setOpenKeywords] = useState<boolean>(false);
|
||||||
|
|
||||||
const sensors = useSensors(useSensor(PointerSensor));
|
const sensors = useSensors(useSensor(PointerSensor));
|
||||||
|
|
||||||
|
|
@ -282,6 +284,15 @@ export default function DraggableTabs({
|
||||||
>
|
>
|
||||||
Config Ram
|
Config Ram
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
color="lime"
|
||||||
|
variant="filled"
|
||||||
|
size="xs"
|
||||||
|
leftSection={<IconSettings size={16} />}
|
||||||
|
onClick={() => setOpenKeywords(true)}
|
||||||
|
>
|
||||||
|
Keywords
|
||||||
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Tabs.List className={classes.list}>
|
<Tabs.List className={classes.list}>
|
||||||
<SortableContext
|
<SortableContext
|
||||||
|
|
@ -430,6 +441,11 @@ export default function DraggableTabs({
|
||||||
opened={openConfigRam}
|
opened={openConfigRam}
|
||||||
onClose={() => setOpenConfigRam(false)}
|
onClose={() => setOpenConfigRam(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ModalKeywords
|
||||||
|
opened={openKeywords}
|
||||||
|
onClose={() => setOpenKeywords(false)}
|
||||||
|
/>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,490 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
Modal,
|
||||||
|
Button,
|
||||||
|
Grid,
|
||||||
|
ScrollArea,
|
||||||
|
Table,
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
TextInput,
|
||||||
|
Select,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import axios from "axios";
|
||||||
|
import type { Keywords } from "../../untils/types";
|
||||||
|
import { IconX } from "@tabler/icons-react";
|
||||||
|
import { notifications } from "@mantine/notifications";
|
||||||
|
import DialogConfirm from "../DialogConfirm";
|
||||||
|
|
||||||
|
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||||
|
const LIST_TYPE = [
|
||||||
|
{ value: "error", label: "Error" },
|
||||||
|
{ value: "warning", label: "Warning" },
|
||||||
|
{ value: "special_model", label: "Special model" },
|
||||||
|
];
|
||||||
|
const LIST_MATCH_TYPE = [
|
||||||
|
{ value: "exact", label: "Exact" },
|
||||||
|
{ value: "include", label: "Include" },
|
||||||
|
];
|
||||||
|
interface Props {
|
||||||
|
opened: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ModalKeywords({ opened, onClose }: Props) {
|
||||||
|
const [keywords, setKeywords] = useState<Keywords[]>([]);
|
||||||
|
const [dataKeywords, setDataKeywords] = useState<Keywords | null>(null);
|
||||||
|
const [newKeywords, setNewKeywords] = useState<Keywords>({
|
||||||
|
name: "",
|
||||||
|
type: "special_model",
|
||||||
|
match_type: "include",
|
||||||
|
is_active: true,
|
||||||
|
});
|
||||||
|
const [inputModel, setInputModel] = useState<string>("");
|
||||||
|
const [disabled, setDisabled] = useState<boolean>(false);
|
||||||
|
const [openConfirm, setOpenConfirm] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// get list keyword
|
||||||
|
const getListConfig = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(apiUrl + "api/keywords");
|
||||||
|
if (response.data.data && Array.isArray(response.data.data)) {
|
||||||
|
setKeywords(response.data.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error get keyword", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (opened) getListConfig();
|
||||||
|
else {
|
||||||
|
setDataKeywords(null);
|
||||||
|
setInputModel("");
|
||||||
|
setNewKeywords({
|
||||||
|
name: "",
|
||||||
|
type: "special_model",
|
||||||
|
match_type: "include",
|
||||||
|
is_active: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [opened]);
|
||||||
|
|
||||||
|
const handleChange = (field: keyof Keywords, value: string | string[]) => {
|
||||||
|
if (!dataKeywords) return;
|
||||||
|
setDataKeywords({
|
||||||
|
...dataKeywords,
|
||||||
|
[field]: value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAdd = async () => {
|
||||||
|
setDisabled(true);
|
||||||
|
try {
|
||||||
|
const response = await axios.post(apiUrl + `api/keywords/create`, {
|
||||||
|
...newKeywords,
|
||||||
|
});
|
||||||
|
|
||||||
|
// update local list
|
||||||
|
setKeywords((prev) => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
...response.data.data,
|
||||||
|
models:
|
||||||
|
typeof response.data.data.models === "string"
|
||||||
|
? JSON.parse(response.data.data.models)
|
||||||
|
: response.data.data.models,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
notifications.show({
|
||||||
|
title: "Success",
|
||||||
|
message: response.data.message,
|
||||||
|
color: "green",
|
||||||
|
});
|
||||||
|
setNewKeywords({
|
||||||
|
name: "",
|
||||||
|
type: "special_model",
|
||||||
|
match_type: "include",
|
||||||
|
is_active: true,
|
||||||
|
});
|
||||||
|
setDisabled(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error save keyword", error);
|
||||||
|
setDisabled(false);
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: error?.response?.data?.message,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Create fail, please try again!",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
setDisabled(true);
|
||||||
|
if (!dataKeywords) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(apiUrl + `api/keywords/update`, {
|
||||||
|
...dataKeywords,
|
||||||
|
});
|
||||||
|
|
||||||
|
// update local list
|
||||||
|
setKeywords((prev) =>
|
||||||
|
prev.map((item) => (item.id === dataKeywords.id ? dataKeywords : item))
|
||||||
|
);
|
||||||
|
|
||||||
|
setDataKeywords(null);
|
||||||
|
setDisabled(false);
|
||||||
|
notifications.show({
|
||||||
|
title: "Success",
|
||||||
|
message: response.data.message,
|
||||||
|
color: "green",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error save keyword", error);
|
||||||
|
setDisabled(false);
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: error?.response?.data?.message,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Update fail, please try again!",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async () => {
|
||||||
|
setDisabled(true);
|
||||||
|
if (!dataKeywords) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(apiUrl + `api/keywords/delete`, {
|
||||||
|
...dataKeywords,
|
||||||
|
});
|
||||||
|
|
||||||
|
// update local list
|
||||||
|
setKeywords((prev) => prev.filter((item) => item.id !== dataKeywords.id));
|
||||||
|
|
||||||
|
setDataKeywords(null);
|
||||||
|
setDisabled(false);
|
||||||
|
notifications.show({
|
||||||
|
title: "Success",
|
||||||
|
message: response.data.message,
|
||||||
|
color: "green",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error save keyword", error);
|
||||||
|
setDisabled(false);
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: error?.response?.data?.message,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Delete fail, please try again!",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setDataKeywords(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredConfigs = () => {
|
||||||
|
const listConfigs = [...keywords].filter((el) => {
|
||||||
|
const model: string = el.name || "";
|
||||||
|
return model.toLowerCase().includes(inputModel.trim().toLowerCase());
|
||||||
|
});
|
||||||
|
return listConfigs;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
size={"70%"}
|
||||||
|
style={{ position: "absolute", left: 0 }}
|
||||||
|
opened={opened}
|
||||||
|
onClose={onClose}
|
||||||
|
title="Config Keywords"
|
||||||
|
>
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col span={12}>
|
||||||
|
<Box style={{ width: "300px", marginBottom: "10px" }}>
|
||||||
|
<TextInput
|
||||||
|
autoCapitalize="on"
|
||||||
|
label="Search model"
|
||||||
|
placeholder="Enter Model"
|
||||||
|
value={inputModel}
|
||||||
|
onChange={(e) => setInputModel(e.currentTarget.value)}
|
||||||
|
size="xs"
|
||||||
|
rightSection={
|
||||||
|
inputModel ? (
|
||||||
|
<IconX
|
||||||
|
size={14}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
onClick={() => setInputModel("")}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
rightSectionPointerEvents="auto"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<hr />
|
||||||
|
<Flex
|
||||||
|
align={"center"}
|
||||||
|
justify={"space-between"}
|
||||||
|
style={{ marginBottom: "10px", marginTop: "10px" }}
|
||||||
|
>
|
||||||
|
<Flex align={"center"} gap={10}>
|
||||||
|
<TextInput
|
||||||
|
label="Name"
|
||||||
|
placeholder="Enter name"
|
||||||
|
style={{ width: "200px" }}
|
||||||
|
value={newKeywords?.name}
|
||||||
|
onChange={(e) =>
|
||||||
|
setNewKeywords({
|
||||||
|
...newKeywords,
|
||||||
|
name: e.currentTarget.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
clearable={false}
|
||||||
|
size="xs"
|
||||||
|
label="Type"
|
||||||
|
placeholder="Select type"
|
||||||
|
data={LIST_TYPE}
|
||||||
|
value={newKeywords?.type}
|
||||||
|
onChange={(value) =>
|
||||||
|
setNewKeywords({
|
||||||
|
...newKeywords,
|
||||||
|
type: value || "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
clearable={false}
|
||||||
|
size="xs"
|
||||||
|
label="Match Type"
|
||||||
|
placeholder="Select match type"
|
||||||
|
data={LIST_MATCH_TYPE}
|
||||||
|
value={newKeywords?.match_type}
|
||||||
|
onChange={(value) =>
|
||||||
|
setNewKeywords({
|
||||||
|
...newKeywords,
|
||||||
|
match_type: value || "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Button
|
||||||
|
disabled={disabled || newKeywords.name.length === 0}
|
||||||
|
size="xs"
|
||||||
|
color="green"
|
||||||
|
onClick={() => handleAdd()}
|
||||||
|
variant="filled"
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
<Box>
|
||||||
|
<ScrollArea
|
||||||
|
h={"calc(75vh - 150px)"}
|
||||||
|
style={{ marginBottom: "20px" }}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
stickyHeader
|
||||||
|
stickyHeaderOffset={-1}
|
||||||
|
striped
|
||||||
|
highlightOnHover
|
||||||
|
withRowBorders
|
||||||
|
withTableBorder
|
||||||
|
withColumnBorders
|
||||||
|
>
|
||||||
|
<Table.Thead style={{ zIndex: 100 }}>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th style={{ textAlign: "center" }}>Name</Table.Th>
|
||||||
|
<Table.Th w={300} style={{ textAlign: "center" }}>
|
||||||
|
Type
|
||||||
|
</Table.Th>
|
||||||
|
<Table.Th w={300} style={{ textAlign: "center" }}>
|
||||||
|
Match Type
|
||||||
|
</Table.Th>
|
||||||
|
<Table.Th w={200} style={{ textAlign: "center" }}>
|
||||||
|
Action
|
||||||
|
</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
|
||||||
|
<Table.Tbody>
|
||||||
|
{filteredConfigs().length > 0 ? (
|
||||||
|
filteredConfigs().map((element) => {
|
||||||
|
const isEditing =
|
||||||
|
dataKeywords?.id === element.id && !openConfirm;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table.Tr key={element.id}>
|
||||||
|
{/* MODELS */}
|
||||||
|
<Table.Td>
|
||||||
|
{" "}
|
||||||
|
<Flex wrap={"wrap"} gap={"4px"}>
|
||||||
|
{isEditing ? (
|
||||||
|
<TextInput
|
||||||
|
w={"100%"}
|
||||||
|
label=""
|
||||||
|
placeholder="Enter model"
|
||||||
|
value={dataKeywords?.name || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleChange("name", e.currentTarget.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
element.name
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Table.Td>
|
||||||
|
|
||||||
|
{/* Type */}
|
||||||
|
<Table.Td style={{ textAlign: "center" }}>
|
||||||
|
{isEditing ? (
|
||||||
|
<Select
|
||||||
|
clearable={false}
|
||||||
|
label="Type"
|
||||||
|
placeholder="Select type"
|
||||||
|
data={LIST_TYPE}
|
||||||
|
value={dataKeywords?.type}
|
||||||
|
onChange={(value) =>
|
||||||
|
handleChange("type", value || "")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
LIST_TYPE.find(
|
||||||
|
(item) => item.value === element.type
|
||||||
|
)?.label || element.type
|
||||||
|
)}
|
||||||
|
</Table.Td>
|
||||||
|
|
||||||
|
{/* Match Type */}
|
||||||
|
<Table.Td style={{ textAlign: "center" }}>
|
||||||
|
{isEditing ? (
|
||||||
|
<Select
|
||||||
|
clearable={false}
|
||||||
|
label="Match Type"
|
||||||
|
placeholder="Select match type"
|
||||||
|
data={LIST_MATCH_TYPE}
|
||||||
|
value={dataKeywords?.match_type}
|
||||||
|
onChange={(value) =>
|
||||||
|
handleChange("match_type", value || "")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
LIST_MATCH_TYPE.find(
|
||||||
|
(item) => item.value === element.match_type
|
||||||
|
)?.label || element.match_type
|
||||||
|
)}
|
||||||
|
</Table.Td>
|
||||||
|
|
||||||
|
{/* ACTION */}
|
||||||
|
<Table.Td>
|
||||||
|
<Flex gap={10} justify="center">
|
||||||
|
{isEditing ? (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
size="xs"
|
||||||
|
color="green"
|
||||||
|
onClick={handleSave}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
size="xs"
|
||||||
|
color="gray"
|
||||||
|
onClick={handleCancel}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
size="xs"
|
||||||
|
onClick={() =>
|
||||||
|
setDataKeywords({ ...element })
|
||||||
|
}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
size="xs"
|
||||||
|
color={"red"}
|
||||||
|
onClick={() => {
|
||||||
|
setDataKeywords({ ...element });
|
||||||
|
setOpenConfirm(true);
|
||||||
|
}}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Td colSpan={4} style={{ textAlign: "center" }}>
|
||||||
|
No keywords found.
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
)}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</ScrollArea>
|
||||||
|
</Box>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<DialogConfirm
|
||||||
|
opened={openConfirm}
|
||||||
|
close={() => {
|
||||||
|
setDataKeywords(null);
|
||||||
|
setOpenConfirm(false);
|
||||||
|
}}
|
||||||
|
message={"Are you sure delete this keyword?"}
|
||||||
|
handle={() => {
|
||||||
|
setOpenConfirm(false);
|
||||||
|
handleDelete();
|
||||||
|
}}
|
||||||
|
centered={true}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -288,3 +288,11 @@ export type ConfigRam = {
|
||||||
ram: string;
|
ram: string;
|
||||||
flash: string;
|
flash: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Keywords = {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
match_type: string;
|
||||||
|
is_active: boolean;
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue