Skip to content

Commit c616adc

Browse files
author
nicocapalbo
committed
feat(services): add service control buttons and status fetching
- Add Start, Stop, Restart buttons with status-based disabling - Implement `getServiceStatus` for fetching service status - Update API payload structure for `updateDMBConfig` - Rename function `setActiveSavedTab` to `setSelectedTab` - Improve UI with gap and padding adjustments refactor(services): clean up unused code - Comment out deprecated `persisting`, `isDMBConfig`, and `downloadLogs` - Update conditional logic for config updates fix(rtl): ensure logs scroll to bottom on addition
1 parent 42eaef0 commit c616adc

3 files changed

Lines changed: 80 additions & 36 deletions

File tree

pages/rtl/index.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ const scrollToBottom = () => {
129129
130130
onMounted(async () => {
131131
subscribeToBus()
132+
// Scroll to bottom when a new log is added
133+
await nextTick(() => {
134+
scrollToBottom();
135+
});
132136
});
133137
134138
</script>

pages/services/[serviceId]/index.vue

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ const serviceConfig = ref(null)
1717
const serviceStatus = ref("Unknown")
1818
const serviceLogs = ref(null)
1919
const isProcessing = ref(false)
20-
const persisting = ref(false)
20+
// const persisting = ref(false)
2121
const successMessage = ref("")
2222
const errorMessage = ref("")
23-
const isDMBConfig = ref(true)
23+
// const isDMBConfig = ref(true)
2424
const configFormat = ref("json")
2525
const filterText = ref("");
2626
const selectedFilter = ref("");
2727
const maxLength = ref(1000);
2828
const logContainer = ref(null);
29-
const selectedTab = ref(1)
29+
const selectedTab = ref(0)
3030
3131
const optionList = computed(() => [
3232
{
@@ -86,14 +86,19 @@ const getLogLevelClass = (log) => {
8686
if (log.includes("INFO")) return "text-green-400";
8787
if (log.includes("DEBUG")) return "text-blue-400";
8888
return "text-gray-400";
89-
};
89+
}
90+
const getServiceStatus = async (processName) => {
91+
try {
92+
serviceStatus.value = await processService.fetchProcessStatus(processName)
93+
} catch (error) {
94+
console.error("Failed to fetch service status:", error);
95+
serviceStatus.value = "Unknown";
96+
}
97+
}
9098
const getDMBConfig = async (processName) => {
9199
try {
92-
93100
service.value = await processService.fetchProcess(processName)
94101
DMBConfig.value = service.value.config_raw || service.value.config
95-
// hasServiceLogs.value = await checkLogsAvailability(service.value.process_name)
96-
serviceStatus.value = await processService.fetchProcessStatus(service.value.process_name)
97102
} catch (error) {
98103
console.error("Failed to load DMB config:", error);
99104
errorMessage.value = "Failed to load DMB configuration.";
@@ -139,32 +144,33 @@ const getLogs = async(processName) => {
139144
serviceLogs.value = "Failed to load logs.";
140145
}
141146
}
142-
const downloadLogs = () => {
143-
const logs = filteredLogs.value.map(({ timestamp, level, process, message }) => {
144-
const d = new Date(timestamp);
145-
const f = n => String(n).padStart(2, '0');
146-
const date = `${f(d.getDate())}/${f(d.getMonth() + 1)}/${d.getFullYear()} ${f(d.getHours())}:${f(d.getMinutes())}:${f(d.getSeconds())}`;
147-
return `[${date}] [${level}] [${process}] ${message}`;
148-
});
147+
// const downloadLogs = () => {
148+
// const logs = filteredLogs.value.map(({ timestamp, level, process, message }) => {
149+
// const d = new Date(timestamp);
150+
// const f = n => String(n).padStart(2, '0');
151+
// const date = `${f(d.getDate())}/${f(d.getMonth() + 1)}/${d.getFullYear()} ${f(d.getHours())}:${f(d.getMinutes())}:${f(d.getSeconds())}`;
152+
// return `[${date}] [${level}] [${process}] ${message}`;
153+
// });
154+
//
155+
// const blob = new Blob([logs.join("\n")], { type: "text/plain" });
156+
// const url = window.URL.createObjectURL(blob);
157+
// const a = document.createElement("a");
158+
// a.href = url;
159+
// a.download = `logs_${service.value.process_name}.log`;
160+
// a.click();
161+
// window.URL.revokeObjectURL(url);
162+
// };
149163
150-
const blob = new Blob([logs.join("\n")], { type: "text/plain" });
151-
const url = window.URL.createObjectURL(blob);
152-
const a = document.createElement("a");
153-
a.href = url;
154-
a.download = `logs_${service.value.process_name}.log`;
155-
a.click();
156-
window.URL.revokeObjectURL(url);
157-
};
158164
const updateConfig = async(persist) => {
159165
isProcessing.value = true;
160-
persisting.value = persist;
166+
// persisting.value = persist;
161167
successMessage.value = "";
162168
errorMessage.value = "";
163169
try {
164-
const { configService } = useService()
165-
if (isDMBConfig.value) {
166-
const configToSend = configFormat.value === "json" ? JSON.parse(serviceConfig.value) : serviceConfig.value;
167-
await configService.updateDMBConfig(service.value.process_name, configToSend, persist);
170+
if (selectedTab.value === 0) {
171+
// const configToSend = configFormat.value === "json" ? JSON.parse(serviceConfig.value) : serviceConfig.value;
172+
const response = await configService.updateDMBConfig(service.value.process_name, DMBConfig.value, persist);
173+
console.log(response);
168174
} else {
169175
await configService.updateServiceConfig(
170176
service.value.process_name,
@@ -218,11 +224,10 @@ const performAction = async(action, successCallback) => {
218224
}
219225
const scrollToBottom = () => {
220226
if (logContainer.value) {
221-
// Smooth scroll is optional; remove behavior for instant scroll
222227
logContainer.value.scrollTo({ top: logContainer.value.scrollHeight, behavior: 'smooth' })
223228
}
224229
};
225-
const setActiveSavedTab = (tabId) => {
230+
const setSelectedTab = (tabId) => {
226231
selectedTab.value = tabId
227232
if (tabId === 2) {
228233
nextTick(() => {
@@ -232,7 +237,7 @@ const setActiveSavedTab = (tabId) => {
232237
}
233238
onMounted(async () => {
234239
process_name_param.value = route.params.serviceId
235-
await Promise.all([getDMBConfig(process_name_param.value), getServiceConfig(process_name_param.value), getLogs(process_name_param.value)])
240+
await Promise.all([getDMBConfig(process_name_param.value), getServiceConfig(process_name_param.value), getLogs(process_name_param.value), getServiceStatus(process_name_param.value)])
236241
loading.value = false
237242
})
238243
</script>
@@ -253,15 +258,49 @@ onMounted(async () => {
253258
/>
254259
</div>
255260
</div>
256-
<TabBar :selected-tab="selectedTab" :option-list="optionList" @selected-tab="setActiveSavedTab" class="mb-2" />
257-
<div v-if="selectedTab === 0" class="grow flex flex-col overflow-hidden">
261+
<TabBar :selected-tab="selectedTab" :option-list="optionList" @selected-tab="setSelectedTab" class="mb-2" />
262+
<div v-if="selectedTab === 0" class="grow flex flex-col overflow-hidden gap-4 pb-4">
258263
<JsonEditorVue
259264
v-model="DMBConfig"
260265
v-bind="{/* local props & attrs */}"
261266
class="jse-theme-dark grow overflow-auto"
262267
/>
268+
269+
<!-- Actions -->
270+
<div class="flex justify-between items-center">
271+
<!-- Start, Stop, Restart Buttons (Left-Aligned) -->
272+
<div class="flex gap-2">
273+
<button @click="startService" :disabled="isProcessing || serviceStatus === PROCESS_STATUS.RUNNING " class="button-small start">
274+
Start
275+
</button>
276+
<button @click="stopService" :disabled="isProcessing || serviceStatus === PROCESS_STATUS.STOPPED" class="button-small stop">
277+
Stop
278+
</button>
279+
<button @click="restartService" :disabled="isProcessing" class="button-small restart">
280+
Restart
281+
</button>
282+
</div>
283+
284+
<!-- Apply and Save Buttons (Right-Aligned) -->
285+
<div class="flex gap-4">
286+
<button @click="updateConfig(false)" :disabled="isProcessing" class="button-small apply">
287+
Apply in Memory
288+
</button>
289+
<button @click="updateConfig(true)" :disabled="isProcessing" class="button-small start">
290+
Save to File
291+
</button>
292+
</div>
293+
</div>
294+
295+
<!-- Success/Failure Messages -->
296+
<div v-if="successMessage" class="text-green-400">
297+
{{ successMessage }}
298+
</div>
299+
<div v-if="errorMessage" class="text-red-400">
300+
{{ errorMessage }}
301+
</div>
263302
</div>
264-
<div v-if="selectedTab === 1" class="grow flex flex-col overflow-hidden">
303+
<div v-if="selectedTab === 1" class="grow flex flex-col overflow-hidden gap-4 pb-4">
265304
<!-- Config Box -->
266305
<JsonEditorVue
267306
v-model="serviceConfig"

services/config.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ export const configRepository =() => ({
3434
},
3535
async updateDMBConfig(processName, updates, persist = false){
3636
try {
37-
const response = await axios.post(`/api/config/update-dmb-config`, {
37+
const payload = {
3838
process_name: processName,
3939
updates,
40-
persist,
41-
});
40+
persist
41+
}
42+
const response = await axios.post(`/api/config/update-dmb-config`, payload);
4243
return response.data;
4344
} catch (error) {
4445
throw error.response || error;

0 commit comments

Comments
 (0)