@@ -8,63 +8,59 @@ import { onMount } from 'svelte';
8
8
import { studioClient } from ' /@/utils/client' ;
9
9
import { tasks } from ' /@/stores/tasks' ;
10
10
import type { Task } from ' @shared/src/models/ITask' ;
11
- import { filterByLabel } from ' /@/utils/taskUtils' ;
12
- import TasksProgress from ' /@/lib/progress/TasksProgress.svelte' ;
13
11
import { inferenceServers } from ' /@/stores/inferenceServers' ;
14
12
import type { ContainerProviderConnectionInfo } from ' @shared/src/models/IContainerConnectionInfo' ;
15
13
import { Button , ErrorMessage , FormPage , Input } from ' @podman-desktop/ui-svelte' ;
16
14
import ModelSelect from ' ../lib/select/ModelSelect.svelte' ;
17
15
import { containerProviderConnections } from ' /@/stores/containerProviderConnections' ;
18
16
import ContainerProviderConnectionSelect from ' /@/lib/select/ContainerProviderConnectionSelect.svelte' ;
19
17
import ContainerConnectionWrapper from ' /@/lib/notification/ContainerConnectionWrapper.svelte' ;
20
- import { get } from ' svelte/store ' ;
18
+ import TrackedTasks from ' /@/lib/progress/TrackedTasks.svelte ' ;
21
19
22
- // The tracking id is a unique identifier provided by the
23
- // backend when calling requestCreateInferenceServer
24
- export let trackingId: string | undefined = undefined ;
20
+ interface Props {
21
+ // The tracking id is a unique identifier provided by the
22
+ // backend when calling requestCreateInferenceServer
23
+ trackingId? : string ;
24
+ }
25
+
26
+ let { trackingId }: Props = $props ();
25
27
26
28
// List of the models available locally
27
- let localModels: ModelInfo [];
28
- $ : localModels = $modelsInfo .filter (model => model .file );
29
+ let localModels: ModelInfo [] = $derived ($modelsInfo .filter (model => model .file ));
29
30
30
31
// The container provider connection to use
31
- let containerProviderConnection: ContainerProviderConnectionInfo | undefined = undefined ;
32
+ let containerProviderConnection: ContainerProviderConnectionInfo | undefined = $state ( undefined ) ;
32
33
33
34
// Filtered connections (started)
34
- let startedContainerProviderConnectionInfo: ContainerProviderConnectionInfo [] = [];
35
- $ : startedContainerProviderConnectionInfo = $containerProviderConnections .filter (
36
- connection => connection .status === ' started' ,
35
+ let startedContainerProviderConnectionInfo: ContainerProviderConnectionInfo [] = $derived (
36
+ $containerProviderConnections .filter (connection => connection .status === ' started' ),
37
37
);
38
38
39
- // Select default connection
40
- $ : if (containerProviderConnection === undefined && startedContainerProviderConnectionInfo .length > 0 ) {
41
- containerProviderConnection = startedContainerProviderConnectionInfo [0 ];
42
- }
43
-
44
39
// The containerPort is the bind value to form input
45
- let containerPort: number | undefined = undefined ;
40
+ let containerPort: number | undefined = $state ( undefined ) ;
46
41
// The model is the bind value to ModelSelect form
47
- let model: ModelInfo | undefined = undefined ;
42
+ let model: ModelInfo | undefined = $state ( undefined ) ;
48
43
// If the creation of a new inference service fail
49
- let errorMsg: string | undefined = undefined ;
50
- // The trackedTasks are the tasks linked to the trackingId
51
- let trackedTasks: Task [];
52
-
53
- // has an error been raised
54
- let error: boolean = false ;
55
-
44
+ let errorMsg: string | undefined = $state (undefined );
56
45
// The containerId will be included in the tasks when the creation
57
46
// process will be completed
58
- let containerId: string | undefined = undefined ;
59
- $ : available = containerId && $inferenceServers .some (server => server .container .containerId );
60
-
61
- $ : loading = trackingId !== undefined && ! error ;
62
-
63
- $ : {
47
+ let containerId: string | undefined = $state (undefined );
48
+ // available means the server is started
49
+ let available: boolean = $derived (!! containerId && $inferenceServers .some (server => server .container .containerId ));
50
+ // loading state
51
+ let loading = $derived (trackingId !== undefined && ! errorMsg );
52
+
53
+ $effect (() => {
54
+ // Select default model
64
55
if (! model && localModels .length > 0 ) {
65
56
model = localModels [0 ];
66
57
}
67
- }
58
+
59
+ // Select default connection
60
+ if (! containerProviderConnection && startedContainerProviderConnectionInfo .length > 0 ) {
61
+ containerProviderConnection = startedContainerProviderConnectionInfo [0 ];
62
+ }
63
+ });
68
64
69
65
const onContainerPortInput = (event : Event ): void => {
70
66
const raw = (event .target as HTMLInputElement ).value ;
@@ -83,11 +79,10 @@ const submit = async (): Promise<void> => {
83
79
if (containerPort === undefined ) throw new Error (' invalid container port' );
84
80
85
81
try {
86
- error = false ;
87
82
const trackingId = await studioClient .requestCreateInferenceServer ({
88
- modelsInfo: [model ],
89
- port: containerPort ,
90
- connection: containerProviderConnection ,
83
+ modelsInfo: [$state . snapshot ( model ) ],
84
+ port: $state . snapshot ( containerPort ) ,
85
+ connection: $state . snapshot ( containerProviderConnection ) ,
91
86
});
92
87
router .location .query .set (' trackingId' , trackingId );
93
88
} catch (err : unknown ) {
@@ -107,32 +102,23 @@ const openServiceDetails = (): void => {
107
102
};
108
103
109
104
// Utility method to filter the tasks properly based on the tracking Id
110
- const processTasks = (tasks : Task []): void => {
111
- if (trackingId === undefined ) {
112
- trackedTasks = [];
113
- return ;
114
- }
115
-
116
- trackedTasks = filterByLabel (tasks , {
117
- trackingId: trackingId ,
118
- });
119
-
105
+ const processTasks = (trackedTasks : Task []): void => {
120
106
// Check for errors
121
107
// hint: we do not need to display them as the TasksProgress component will
122
- error = trackedTasks .find (task => task .error )?.error !== undefined ;
108
+ errorMsg = trackedTasks .find (task => task .error )?.error ;
123
109
124
110
const task: Task | undefined = trackedTasks .find (task => ' containerId' in (task .labels ?? {}));
125
111
if (task === undefined ) return ;
126
112
127
113
containerId = task .labels ?.[' containerId' ];
128
114
129
115
// if we re-open the page, we might need to restore the model selected
130
- populateModelFromTasks ();
116
+ populateModelFromTasks (trackedTasks );
131
117
};
132
118
133
119
// This method uses the trackedTasks to restore the selected value of model
134
120
// It is useful when the page has been restored
135
- function populateModelFromTasks(): void {
121
+ function populateModelFromTasks(trackedTasks : Task [] ): void {
136
122
const task = trackedTasks .find (
137
123
task => task .labels && ' model-id' in task .labels && typeof task .labels [' model-id' ] === ' string' ,
138
124
);
@@ -145,26 +131,21 @@ function populateModelFromTasks(): void {
145
131
model = mModel ;
146
132
}
147
133
148
- $ : if (typeof trackingId === ' string' && trackingId .length > 0 ) {
149
- refreshTasks ();
150
- }
151
-
152
- function refreshTasks(): void {
153
- processTasks (get (tasks ));
154
- }
155
-
156
- onMount (async () => {
157
- containerPort = await studioClient .getHostFreePort ();
134
+ onMount (() => {
135
+ studioClient
136
+ .getHostFreePort ()
137
+ .then (port => {
138
+ containerPort = port ;
139
+ })
140
+ .catch ((err : unknown ) => {
141
+ console .error (err );
142
+ });
158
143
159
144
// we might have a query parameter, then we should use it
160
145
const queryModelId = router .location .query .get (' model-id' );
161
146
if (queryModelId !== undefined && typeof queryModelId === ' string' ) {
162
147
model = localModels .find (mModel => mModel .id === queryModelId );
163
148
}
164
-
165
- tasks .subscribe (tasks => {
166
- processTasks (tasks );
167
- });
168
149
});
169
150
170
151
export function goToUpPage(): void {
@@ -189,16 +170,14 @@ export function goToUpPage(): void {
189
170
<!-- warning machine resources -->
190
171
{#if containerProviderConnection }
191
172
<div class =" mx-5" >
192
- <ContainerConnectionWrapper model ={model } containerProviderConnection ={containerProviderConnection } />
173
+ <ContainerConnectionWrapper
174
+ model ={$state .snapshot (model )}
175
+ containerProviderConnection ={$state .snapshot (containerProviderConnection )} />
193
176
</div >
194
177
{/if }
195
178
196
179
<!-- tasks tracked -->
197
- {#if trackedTasks ?.length > 0 }
198
- <div class =" mx-5 mt-5" role =" status" >
199
- <TasksProgress tasks ={trackedTasks } />
200
- </div >
201
- {/if }
180
+ <TrackedTasks onChange ={processTasks } class ="mx-5 mt-5" trackingId ={trackingId } tasks ={$tasks } />
202
181
203
182
<!-- form -->
204
183
<div class =" bg-[var(--pd-content-card-bg)] m-5 space-y-6 px-8 sm:pb-6 xl:pb-8 rounded-lg h-fit" >
0 commit comments