feat: recipe version selector

- fix recipe not show on overview
- fix recipe show late after select country
- disable queue message on no connection ws
- fix infinite topping(s) list if moving between pages

Signed-off-by: pakintada@gmail.com <Pakin>
This commit is contained in:
pakintada@gmail.com 2026-05-04 16:50:15 +07:00
parent e25881d016
commit a29ff0be1a
19 changed files with 314 additions and 108 deletions

View file

@ -5,11 +5,10 @@ Idea, Issue, Work Tracking
[Pending] [Pending]
- [] #2: Send change value from editing in recipe to machine
- [] #3: Save value to recipe - [] #3: Save value to recipe
- [] #5: revert value on close dialog recipe
- [] #6: display all recipes with materials from csv [material usages with product code] - [] #6: display all recipes with materials from csv [material usages with product code]
- [] #7: material & menu creation - [] #7: material & menu creation
- [x] #8: change recipe version
[Rejected] [Rejected]
- [] #4: From #1, will do sync value from server, so that user could save their current edit too - [] #4: From #1, will do sync value from server, so that user could save their current edit too
@ -17,5 +16,7 @@ Idea, Issue, Work Tracking
[Done] [Done]
- [x] #1: Topping value saving bug, fix by snapshot value - [x] #1: Topping value saving bug, fix by snapshot value
- [x] #2: Send change value from editing in recipe to machine
- [x] #5: revert value on close dialog recipe

View file

@ -249,7 +249,7 @@
<Tabs.Content value="details"> <Tabs.Content value="details">
<!-- hide by machine state --> <!-- hide by machine state -->
{#if $machineInfoStore?.status == 'IDLE' || $machineInfoStore?.status == ''} {#if $machineInfoStore?.status == 'IDLE' || $machineInfoStore?.status == '' || refPage == 'overview'}
<RecipelistTable <RecipelistTable
data={recipeListMatState} data={recipeListMatState}
{columns} {columns}

View file

@ -293,11 +293,11 @@
// console.log('sheet open? ', sheetOpenState); // console.log('sheet open? ', sheetOpenState);
let refFrom = get(referenceFromPage); let refFrom = get(referenceFromPage);
categories = get( categories = $state.snapshot(
refFrom === 'overview' ? toppingGroupFromServerQuery : toppingGroupFromMachineQuery get(refFrom === 'overview' ? toppingGroupFromServerQuery : toppingGroupFromMachineQuery)
); );
topping_lists = get( topping_lists = $state.snapshot(
refFrom === 'overview' ? toppingListFromServerQuery : toppingListFromMachineQuery get(refFrom === 'overview' ? toppingListFromServerQuery : toppingListFromMachineQuery)
); );
// save ref // save ref

View file

@ -208,6 +208,9 @@
let current_selected = selectableToppingInGroup.find( let current_selected = selectableToppingInGroup.find(
(x) => x.id === currentToppings[getToppingSlot()]['ListGroupID'][0] (x) => x.id === currentToppings[getToppingSlot()]['ListGroupID'][0]
); );
console.log('current selected topping list', row_uid, current_selected);
if (currentToppings[getToppingSlot()]['ListGroupID'][0] === 0) { if (currentToppings[getToppingSlot()]['ListGroupID'][0] === 0) {
return 'Empty'; return 'Empty';
} }

View file

@ -130,19 +130,32 @@
}); });
} else { } else {
// topping part // topping part
latestRecipeToppingData.set(new_topping_value_for_save); // latestRecipeToppingData.set(new_topping_value_for_save);
console.log('save change', get(latestRecipeToppingData)); // console.log('save change', get(latestRecipeToppingData));
currentData['ToppingSet'] = latestRecipeToppingData; // currentData['ToppingSet'] = latestRecipeToppingData;
console.log('current data', currentData); // console.log('current data', currentData);
if (get(referenceFromPage) == 'brew') { if (get(referenceFromPage) == 'brew') {
// send change to machine // send change to machine
// apply value
let recipeDevSnapshot = get(recipeFromMachineQuery) ?? {};
let recipe01Snap = recipeDevSnapshot['recipe'];
if (recipe01Snap) {
recipe01Snap[ready_to_send_brew[0]['productCode']] = ready_to_send_brew[0];
// save now
recipeDevSnapshot['recipe'] = recipe01Snap;
recipeFromMachineQuery.set(recipeDevSnapshot);
}
sendToAndroid({ sendToAndroid({
type: 'save_recipe_machine', type: 'save_recipe_machine',
payload: { payload: {
time: new Date().toLocaleTimeString(), time: new Date().toLocaleTimeString(),
data: currentData data: ready_to_send_brew[0]
} }
}); });
} else if (get(referenceFromPage) == 'overview') { } else if (get(referenceFromPage) == 'overview') {
@ -294,10 +307,10 @@
<Dialog.Title <Dialog.Title
>Edit Recipe {productCode} >Edit Recipe {productCode}
<Badge class="m-2"> <Badge class="m-2">
{#if $machineInfoStore?.status == 'IDLE' || $machineInfoStore?.status == ''} {#if $machineInfoStore?.status == 'IDLE' || $machineInfoStore?.status == '' || refPage == 'overview'}
Ready Ready
{:else} {:else}
<Spinner /> Brewing <Spinner /> Working
{/if} {/if}
</Badge> </Badge>
</Dialog.Title> </Dialog.Title>
@ -317,7 +330,7 @@
on:saveRecipe={async () => { on:saveRecipe={async () => {
save_change = true; save_change = true;
console.log('save change, check state', callback_revert_value_if_not_save); callback_revert_value_if_not_save(save_change);
addNotification('INFO:Save recipe'); addNotification('INFO:Save recipe');
}} }}

View file

@ -224,7 +224,7 @@ async function connectToAndroidServer() {
return; return;
} }
await push('/sdcard/coffeevending/enable_adb_block_watch', '1'); // await push('/sdcard/coffeevending/enable_adb_block_watch', '1');
const stream = await inst.transport.connect(env.PUBLIC_BREW_CONN_PORT); const stream = await inst.transport.connect(env.PUBLIC_BREW_CONN_PORT);
const writer = stream.writable.getWriter(); const writer = stream.writable.getWriter();

View file

@ -6,6 +6,7 @@ import { extractCookieOnNonBrowser } from '$lib/helpers/cookie';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { permission } from '../stores/permissions'; import { permission } from '../stores/permissions';
import { addNotification } from '../stores/noti'; import { addNotification } from '../stores/noti';
import { recipeData, recipeOverviewData } from '../stores/recipeStore';
export async function getRecipes() { export async function getRecipes() {
if (browser && !get(departmentStore)) { if (browser && !get(departmentStore)) {
@ -31,7 +32,10 @@ export async function getRecipes() {
// construct path. fetch (GET) {server}/recipe/{countryTarget}/{version} // construct path. fetch (GET) {server}/recipe/{countryTarget}/{version}
let idToken = await get(auth)?.getIdToken(); let idToken = await get(auth)?.getIdToken();
console.log('country target get recipe', country); console.log('country target get recipe', countryTarget);
recipeData.set([]);
recipeOverviewData.set([]);
sendMessage({ sendMessage({
type: 'recipe', type: 'recipe',
@ -46,3 +50,48 @@ export async function getRecipes() {
return []; return [];
} }
export async function getRecipeWithVersion(version: string) {
if (browser && !get(departmentStore)) {
console.log('cannot get dep', get(departmentStore));
return [];
}
let countryTarget = get(departmentStore);
let country = '';
let countryPerm = `document.read.${countryTarget}`;
let user_perms = get(permission);
if (!user_perms.includes(countryPerm)) {
addNotification('ERR:Invalid permission');
return [];
}
// if (!countryTarget && !browser) {
// countryTarget = extractCookieOnNonBrowser()['department'];
// }
// construct path. fetch (GET) {server}/recipe/{countryTarget}/{version}
let idToken = await get(auth)?.getIdToken();
console.log('country target get recipe', countryTarget);
recipeData.set([]);
recipeOverviewData.set([]);
// NOTE: although version is provided, actual version field is still need to be latest
// Just in case version is not found
sendMessage({
type: 'recipe',
payload: {
auth: idToken ?? '',
partial: false,
country: countryTarget ?? '',
version: -1,
parameters: 'use_legacy_version=true,version=' + version
}
});
return [];
}

View file

@ -1,5 +1,6 @@
import { updateMachineStatus } from '../stores/machineInfoStore'; import { updateMachineStatus } from '../stores/machineInfoStore';
import { addNotification } from '../stores/noti'; import { addNotification } from '../stores/noti';
import { handleIncomingMessages } from './messageHandler';
type AdbPayload = { type: string; payload: any }; type AdbPayload = { type: string; payload: any };
@ -17,6 +18,26 @@ async function handleAdbPayload(raw_payload: string) {
case 'response': case 'response':
if (payload.payload instanceof String) { if (payload.payload instanceof String) {
// single message response // single message response
let raw_payload = payload.payload.toString();
if (raw_payload.startsWith('save_recipe_machine')) {
let res = raw_payload.split('/');
let pd = res[1] ?? '';
let action = res[2] ?? '';
let uiAction = res[3] ?? '';
handleIncomingMessages(
JSON.stringify({
type: 'ui_action',
payload: {
action: uiAction,
from: 'brew',
ref: `${pd}.${action}`
}
})
);
}
} }
break; break;
case 'ACK': case 'ACK':

View file

@ -1,6 +1,7 @@
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import { addNotification, notiStore } from '../stores/noti'; import { addNotification, notiStore } from '../stores/noti';
import { import {
currentRecipeVersionsSelector,
materialFromServerQuery, materialFromServerQuery,
recipeData, recipeData,
recipeDataError, recipeDataError,
@ -12,6 +13,8 @@ import {
} from '../stores/recipeStore'; } from '../stores/recipeStore';
import { buildOverviewFromServer } from '$lib/data/recipeService'; import { buildOverviewFromServer } from '$lib/data/recipeService';
import { auth } from '../client/firebase'; import { auth } from '../client/firebase';
import { type RecipeVersion } from '$lib/models/recipe_version.model';
import { goto } from '$app/navigation';
export const messages = writable<string[]>([]); export const messages = writable<string[]>([]);
@ -32,18 +35,30 @@ const handlers: Record<string, (payload: any) => void> = {
let stream_id = p.stream_id; let stream_id = p.stream_id;
let total_size = p.total_size; let total_size = p.total_size;
let chunk_size = p.chunk_size; let chunk_size = p.chunk_size;
let data_meta = p.metadata;
if (stream_id) { if (stream_id) {
addNotification('INFO:Start streaming data'); addNotification('INFO:Start streaming data');
let meta_list = data_meta?.split(',');
let version = meta_list[0]?.split('=')[1] ?? '';
let country = meta_list[1]?.split('=')[1] ?? '';
// recipeLoading.set(true); // recipeLoading.set(true);
recipeStreamMeta.set({ recipeStreamMeta.set({
id: stream_id, id: stream_id,
total_size: total_size, total_size: total_size,
chunk_size: chunk_size, chunk_size: chunk_size,
progress: 0 progress: 0,
version,
country
}); });
recipeData.set([]); recipeData.set([]);
recipeOverviewData.set([]); recipeOverviewData.set([]);
materialFromServerQuery.set([]);
toppingListFromServerQuery.set([]);
toppingGroupFromServerQuery.set([]);
} }
}, },
stream_data_error: (p) => { stream_data_error: (p) => {
@ -56,6 +71,7 @@ const handlers: Record<string, (payload: any) => void> = {
}, },
stream_data_chunk: (p) => { stream_data_chunk: (p) => {
let current_meta = get(recipeStreamMeta); let current_meta = get(recipeStreamMeta);
// console.log('current meta', current_meta);
if (current_meta) { if (current_meta) {
let stream_id = current_meta.id; let stream_id = current_meta.id;
@ -92,6 +108,7 @@ const handlers: Record<string, (payload: any) => void> = {
// build overview for recipe from server // build overview for recipe from server
// //
// console.log('ending stream');
buildOverviewFromServer(); buildOverviewFromServer();
}, },
stream_data_extra: (p) => { stream_data_extra: (p) => {
@ -120,7 +137,7 @@ const handlers: Record<string, (payload: any) => void> = {
curr_mat_query.push(m); curr_mat_query.push(m);
} }
// console.log('current materials: ', JSON.stringify(curr_mat_query)); // // console.log('current materials: ', JSON.stringify(curr_mat_query));
materialFromServerQuery.set(curr_mat_query); materialFromServerQuery.set(curr_mat_query);
break; break;
case 'topplist': case 'topplist':
@ -168,6 +185,28 @@ const handlers: Record<string, (payload: any) => void> = {
// broadcast to all // broadcast to all
addNotification(`${noti_level}:${msg}`); addNotification(`${noti_level}:${msg}`);
} }
},
ui_action: (p) => {
if (p.action == 'refreshNow' && p.from == 'brew') {
goto('/tools/brew');
}
},
version_selectors: (p) => {
if (p.versions.length > 0) {
currentRecipeVersionsSelector.set([]);
let result: RecipeVersion[] = [];
for (let vstr of p.versions) {
let pure_version = vstr.split('_')[0];
result.push({
display_version: pure_version,
actual_version_name: vstr
});
}
currentRecipeVersionsSelector.set(result);
}
} }
}; };

View file

@ -41,25 +41,25 @@ export function sendCommandRequest(target: CommandRequest, values: any) {
}); });
} }
export function sendMessage(msg: OutMessage): boolean { export function sendMessage(msg: OutMessage, ignore_queue_request: boolean = true): boolean {
const socket = get(socketStore); const socket = get(socketStore);
const data = JSON.stringify(msg); const data = JSON.stringify(msg);
// console.log('try sending ', data); // console.log('try sending ', data);
if (!socket || socket.readyState !== WebSocket.OPEN) { if (!socket || socket.readyState !== WebSocket.OPEN) {
console.warn('WebSocket not connected, put to queue'); // console.warn('WebSocket not connected, put to queue');
let currentQueue = get(queue); // let currentQueue = get(queue);
if (currentQueue.length >= 10) { // if (currentQueue.length >= 10) {
while (currentQueue.length >= 10) { // while (currentQueue.length >= 10) {
currentQueue.shift(); // currentQueue.shift();
} // }
} // }
currentQueue.push(data); // currentQueue.push(data);
queue.set(currentQueue); // queue.set(currentQueue);
addNotification('WARN:Queuing request'); // if (!ignore_queue_request) addNotification('WARN:Queuing request');
return false; return false;
} }

View file

@ -1,6 +1,7 @@
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import type { RecipeOverview } from '../../../routes/(authed)/recipe/overview/columns'; import type { RecipeOverview } from '../../../routes/(authed)/recipe/overview/columns';
import type { Material } from '$lib/models/material.model'; import type { Material } from '$lib/models/material.model';
import type { RecipeVersion } from '$lib/models/recipe_version.model';
export const recipeData = writable<any>(null); export const recipeData = writable<any>(null);
export const recipeLoading = writable(false); export const recipeLoading = writable(false);
@ -10,8 +11,12 @@ export const recipeStreamMeta = writable<{
total_size: number; total_size: number;
chunk_size: number; chunk_size: number;
progress: number; progress: number;
version?: string;
country?: string;
} | null>(null); } | null>(null);
export const currentRecipeVersionsSelector = writable<RecipeVersion[]>([]);
// from server // from server
export const recipeOverviewData = writable<RecipeOverview[] | null>(null); export const recipeOverviewData = writable<RecipeOverview[] | null>(null);
export const materialData = writable<Material | undefined>(); export const materialData = writable<Material | undefined>();
@ -45,41 +50,3 @@ export const materialFromMachineQuery = writable<any>({});
export const referenceFromPage = writable<string>(''); export const referenceFromPage = writable<string>('');
export const currentEditingRecipeProductCode = writable<string>(''); export const currentEditingRecipeProductCode = writable<string>('');
let worker: Worker | null = null;
let initialized = false;
export function loadRecipe(url: string) {
if (initialized) return;
initialized = true;
recipeLoading.set(true);
worker = new Worker(new URL('../../workers/data.worker.ts', import.meta.url), {
type: 'module'
});
worker.onmessage = (e) => {
const { type, payload } = e.data;
if (type === 'data') {
recipeData.set(payload);
recipeLoading.set(false);
}
if (type === 'error') {
recipeDataError.set(payload);
recipeLoading.set(false);
}
};
worker.postMessage({ url });
}
export function getWorker() {
if (!worker) {
worker = new Worker(new URL('../../workers/data.worker.ts', import.meta.url), {
type: 'module'
});
}
return worker;
}

View file

@ -43,15 +43,15 @@ export function connectToWebsocket() {
} }
// recover messages on connect, flushing // recover messages on connect, flushing
while (get(msgQueue).length) { // while (get(msgQueue).length) {
let queue = get(msgQueue); // let queue = get(msgQueue);
let current = queue.shift(); // let current = queue.shift();
if (current && socket) { // if (current && socket) {
socket.send(current); // socket.send(current);
// set next // // set next
msgQueue.set(queue); // msgQueue.set(queue);
} // }
} // }
// heartbeat 10s // heartbeat 10s
setInterval(() => { setInterval(() => {

View file

@ -4,7 +4,7 @@ export type OutMessage =
| { type: 'lock'; payload: { field: string } } | { type: 'lock'; payload: { field: string } }
| { type: 'general'; payload: string } | { type: 'general'; payload: string }
| { | {
type: 'recipe'; type: 'recipe' | 'recipe_versions';
payload: { payload: {
auth: string; auth: string;
partial: boolean; partial: boolean;

View file

@ -110,7 +110,10 @@ function buildOverviewFromServer() {
let r01_query: any = {}; let r01_query: any = {};
if (server_recipe01) { // console.log('server recipe 01: ', server_recipe01);
if (server_recipe01 != null) {
// console.log('building overview from server');
recipeOverviewData.set([]); recipeOverviewData.set([]);
for (let rp of server_recipe01) { for (let rp of server_recipe01) {
result.push({ result.push({

View file

@ -0,0 +1,4 @@
export interface RecipeVersion {
display_version: string;
actual_version_name: string;
}

View file

@ -10,7 +10,7 @@
import { addNotification } from '$lib/core/stores/noti'; import { addNotification } from '$lib/core/stores/noti';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { setCookieOnNonBrowser } from '$lib/helpers/cookie'; import { setCookieOnNonBrowser } from '$lib/helpers/cookie';
import { referenceFromPage} from '$lib/core/stores/recipeStore'; import { referenceFromPage } from '$lib/core/stores/recipeStore';
let enabledAccessibleCountries: string[] = $state([]); let enabledAccessibleCountries: string[] = $state([]);
@ -23,6 +23,7 @@
addNotification(`INFO:Selected ${cnt}`); addNotification(`INFO:Selected ${cnt}`);
setTimeout(async () => { setTimeout(async () => {
console.log(get(departmentStore)); console.log(get(departmentStore));
departmentStore.set(cnt);
if (refPage === 'sheet') { if (refPage === 'sheet') {
await goto('/sheet/overview'); await goto('/sheet/overview');

View file

@ -1,25 +1,30 @@
<script lang="ts"> <script lang="ts">
import Button from '$lib/components/ui/button/button.svelte'; import Button, { buttonVariants } from '$lib/components/ui/button/button.svelte';
import Input from '$lib/components/ui/input/input.svelte'; import Input from '$lib/components/ui/input/input.svelte';
import { SearchIcon } from '@lucide/svelte/icons'; import { SearchIcon, RefreshCcw } from '@lucide/svelte/icons';
import Spinner from '$lib/components/ui/spinner/spinner.svelte'; import Spinner from '$lib/components/ui/spinner/spinner.svelte';
import * as Dialog from '$lib/components/ui/dialog/index';
import Label from '$lib/components/ui/label/label.svelte';
import * as Select from '$lib/components/ui/select/index';
import DataTable from './data-table.svelte'; import DataTable from './data-table.svelte';
import { columns, type RecipeOverview } from './columns'; import { columns, type RecipeOverview } from './columns';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { import {
loadRecipe, currentRecipeVersionsSelector,
recipeData, recipeData,
recipeFromServerQuery, recipeFromServerQuery,
recipeLoading, recipeLoading,
recipeOverviewData, recipeOverviewData,
recipeStreamMeta,
referenceFromPage referenceFromPage
} from '$lib/core/stores/recipeStore.js'; } from '$lib/core/stores/recipeStore.js';
import { sendMessage } from '$lib/core/handlers/ws_messageSender.js'; import { sendMessage } from '$lib/core/handlers/ws_messageSender.js';
import { auth } from '$lib/core/stores/auth.js'; import { auth } from '$lib/core/stores/auth.js';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { getRecipes } from '$lib/core/client/server.js'; import { getRecipes, getRecipeWithVersion } from '$lib/core/client/server.js';
import { permission } from '$lib/core/stores/permissions'; import { permission } from '$lib/core/stores/permissions';
import type { RecipeVersion } from '$lib/models/recipe_version.model';
let data: { recipes: RecipeOverview[] } = $state({ let data: { recipes: RecipeOverview[] } = $state({
recipes: [] recipes: []
@ -27,15 +32,52 @@
let isRecipeLoading = $state(false); let isRecipeLoading = $state(false);
let version: string = $state('');
let country: string = $state('');
let value = $state('');
let version_list: RecipeVersion[] = $state([]);
const triggerVersion = $derived(
version_list.find((f) => f.actual_version_name === value)?.display_version ?? version
);
let unsubRecipeData = recipeOverviewData.subscribe((rd) => { let unsubRecipeData = recipeOverviewData.subscribe((rd) => {
if (rd) { if (rd) {
data.recipes = rd == null ? [] : rd; data.recipes = rd == null ? [] : rd;
let meta_snap = $state.snapshot(get(recipeStreamMeta));
country = meta_snap?.country ?? '...';
version = (meta_snap?.version ?? '...').split('_')[0];
} }
}); });
let unsubRecipeVersion = currentRecipeVersionsSelector.subscribe((vs) => {
if (vs.length > 0) {
version_list = vs;
}
});
function sendGetRecipeVersions(country: string) {
version_list = [];
sendMessage({
type: 'recipe_versions',
payload: {
auth: '',
partial: false,
country: country,
version: -1,
parameters: ''
}
});
}
function sendGetRecipeByVersionSelector() {
getRecipeWithVersion(value);
}
onMount(async () => { onMount(async () => {
// do load recipe // do load recipe
// loadRecipe();
referenceFromPage.set('overview'); referenceFromPage.set('overview');
await getRecipes(); await getRecipes();
@ -43,6 +85,7 @@
onDestroy(() => { onDestroy(() => {
unsubRecipeData(); unsubRecipeData();
unsubRecipeVersion();
}); });
$effect(() => { $effect(() => {
@ -57,6 +100,9 @@
// setTimeout(() => recipeLoading.set(false), 3000); // setTimeout(() => recipeLoading.set(false), 3000);
} }
}, 30000); }, 30000);
version_list = get(currentRecipeVersionsSelector);
return () => { return () => {
clearInterval(recipeFetchInterval); clearInterval(recipeFetchInterval);
}; };
@ -68,10 +114,64 @@
<div class="w-full"> <div class="w-full">
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<div> <div>
<h1 class="m-8 text-4xl font-bold">Overview</h1> <h1 class="m-8 text-4xl font-bold">Overview [ {country} ] version [ {version} ]</h1>
<p class="mx-8 my-0 text-muted-foreground">
Display menus from the current selected country <div class="flex flex-row">
</p> <p class="mx-8 my-0 text-muted-foreground">
Display menus from the current selected country
</p>
<!-- <Button variant="default" onclick={() => sendGetRecipeVersions(country)}>
<span class="flex flex-row gap-2"> <RefreshCcw /> Change Version </span>
</Button> -->
<!-- dialog select version -->
<Dialog.Root>
<Dialog.Trigger
type="button"
class={buttonVariants({ variant: 'outline' })}
onclick={() => sendGetRecipeVersions(country)}
>
<span class="flex flex-row gap-2"> <RefreshCcw /> Change Version </span>
</Dialog.Trigger>
<Dialog.Content class="sm:max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Select Legacy Versions</Dialog.Title>
<Dialog.Description>Viewing the previous version of recipe.</Dialog.Description>
</Dialog.Header>
<div class="grid gap-4">
<!-- <div class="grid gap-3">
<Label for="name-1">Version</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div> -->
<Select.Root type="single" name="selectVersion" bind:value>
<Select.Trigger class="w-[180px]">
{triggerVersion}
</Select.Trigger>
<Select.Content>
{#each version_list as version_n (version_n.actual_version_name)}
<Select.Item
value={version_n.actual_version_name}
label={version_n.display_version}
>
{version_n.display_version}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<Dialog.Footer>
<Dialog.Close type="button" class={buttonVariants({ variant: 'outline' })}>
Cancel
</Dialog.Close>
<Button type="submit" onclick={() => sendGetRecipeByVersionSelector()}>Ok</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
</div>
</div> </div>
<div class="mx-8 my-4 flex gap-2"> <div class="mx-8 my-4 flex gap-2">
<Button variant="default">+ Create Menu</Button> <Button variant="default">+ Create Menu</Button>

View file

@ -5,7 +5,6 @@
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { import {
loadRecipe,
recipeData, recipeData,
recipeFromServerQuery, recipeFromServerQuery,
recipeOverviewData, recipeOverviewData,
@ -21,7 +20,6 @@
onMount(async () => { onMount(async () => {
// do load recipe // do load recipe
// loadRecipe();
refDepartment = get(departmentStore); refDepartment = get(departmentStore);
referenceFromPage.set('overview'); referenceFromPage.set('overview');

View file

@ -28,6 +28,7 @@
import { deviceCredentialManager } from '$lib/core/adb/deviceCredManager'; import { deviceCredentialManager } from '$lib/core/adb/deviceCredManager';
import { afterNavigate } from '$app/navigation'; import { afterNavigate } from '$app/navigation';
import { env } from '$env/dynamic/public'; import { env } from '$env/dynamic/public';
import { fade } from 'svelte/transition';
const sourceDir = '/sdcard/coffeevending'; const sourceDir = '/sdcard/coffeevending';
@ -41,6 +42,9 @@
let brew_status: string = $state(''); let brew_status: string = $state('');
// refresh command
let refresh_counter: number = $state(0);
async function startFetchRecipeFromMachine() { async function startFetchRecipeFromMachine() {
let instance = adb.getAdbInstance(); let instance = adb.getAdbInstance();
// recipeFromMachineLoading.set(true); // recipeFromMachineLoading.set(true);
@ -49,7 +53,7 @@
if (instance) { if (instance) {
console.log('instance passed!'); console.log('instance passed!');
let dev_recipe = await adb.pull(`${sourceDir}/cfg/recipe_branch_dev.json`); let dev_recipe = await adb.pull(`${sourceDir}/cfg/recipe_branch_dev.json`);
console.log('dev recipe ok', dev_recipe != undefined); console.log('dev recipe ok', dev_recipe != undefined, dev_recipe);
if (dev_recipe) { if (dev_recipe) {
if (dev_recipe.length == 0) { if (dev_recipe.length == 0) {
// case error, do last retry // case error, do last retry
@ -69,7 +73,7 @@
// from recipe_branch_dev // from recipe_branch_dev
devRecipe = JSON.parse(dev_recipe); devRecipe = JSON.parse(dev_recipe);
// recipeFromMachineLoading.set(false); // recipeFromMachineLoading.set(false);
addNotification('INFO:Fetch recipe success!'); // addNotification('INFO:Fetch recipe success!');
buildOverviewForBrewing(); buildOverviewForBrewing();
} }
@ -176,6 +180,7 @@
} }
afterNavigate(async () => { afterNavigate(async () => {
console.log('after navigate brew');
await startFetchRecipeFromMachine(); await startFetchRecipeFromMachine();
}); });
@ -314,14 +319,14 @@
let currentQuery = get(recipeFromMachineQuery); let currentQuery = get(recipeFromMachineQuery);
currentQuery = { currentQuery = {
recipe: recipe01_query, ...currentQuery,
...currentQuery recipe: recipe01_query
}; };
let currentMaterialsQuery = materialFromMachine; let currentMaterialsQuery = materialFromMachine;
currentQuery = { currentQuery = {
material: currentMaterialsQuery, ...currentQuery,
...currentQuery material: currentMaterialsQuery
}; };
recipeFromMachineQuery.set(currentQuery); recipeFromMachineQuery.set(currentQuery);
@ -404,15 +409,17 @@
<!-- search bar --> <!-- search bar -->
<div class="w-full"> {#key refresh_counter}
{#if $recipeFromMachineLoading} <div class="w-full">
<div class="flex items-center justify-center"> {#if $recipeFromMachineLoading}
<p class="mx-4">Please wait</p> <div class="flex items-center justify-center">
<Spinner /> <p class="mx-4">Please wait</p>
</div> <Spinner />
{:else} </div>
<DataTable data={data.recipes} refPage="brew" {columns} /> {:else}
{/if} <DataTable data={data.recipes} refPage="brew" {columns} />
</div> {/if}
</div>
{/key}
</div> </div>
</div> </div>