|  | @@ -1,31 +1,33 @@
 | 
	
		
			
				|  |  |  <script lang="ts">
 | 
	
		
			
				|  |  |  	import { v4 as uuidv4 } from 'uuid';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	import { toast } from 'svelte-sonner';
 | 
	
		
			
				|  |  | +	import { models } from '$lib/stores';
 | 
	
		
			
				|  |  |  	import { getContext, onMount, tick } from 'svelte';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  	import type { Writable } from 'svelte/store';
 | 
	
		
			
				|  |  |  	import type { i18n as i18nType } from 'i18next';
 | 
	
		
			
				|  |  | -	import { stringify } from 'postcss';
 | 
	
		
			
				|  |  |  	import {
 | 
	
		
			
				|  |  |  		getPipelineValves,
 | 
	
		
			
				|  |  |  		getPipelineValvesSpec,
 | 
	
		
			
				|  |  |  		updatePipelineValves,
 | 
	
		
			
				|  |  |  		getPipelines,
 | 
	
		
			
				|  |  | -		getModels
 | 
	
		
			
				|  |  | +		getModels,
 | 
	
		
			
				|  |  | +		getPipelinesList
 | 
	
		
			
				|  |  |  	} from '$lib/apis';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	import Spinner from '$lib/components/common/Spinner.svelte';
 | 
	
		
			
				|  |  | -	import { toast } from 'svelte-sonner';
 | 
	
		
			
				|  |  | -	import { models } from '$lib/stores';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	const i18n: Writable<i18nType> = getContext('i18n');
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	export let saveHandler: Function;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	let PIPELINES_LIST = null;
 | 
	
		
			
				|  |  | +	let selectedPipelinesUrlIdx = '';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	let pipelines = null;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	let valves = null;
 | 
	
		
			
				|  |  |  	let valves_spec = null;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  	let selectedPipelineIdx = null;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	const updateHandler = async () => {
 | 
	
	
		
			
				|  | @@ -54,6 +56,9 @@
 | 
	
		
			
				|  |  |  	};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	const getValves = async (idx) => {
 | 
	
		
			
				|  |  | +		valves = null;
 | 
	
		
			
				|  |  | +		valves_spec = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		valves_spec = await getPipelineValvesSpec(localStorage.token, pipelines[idx].id);
 | 
	
		
			
				|  |  |  		valves = await getPipelineValves(localStorage.token, pipelines[idx].id);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -63,7 +68,11 @@
 | 
	
		
			
				|  |  |  	};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	const setPipelines = async () => {
 | 
	
		
			
				|  |  | -		pipelines = await getPipelines(localStorage.token);
 | 
	
		
			
				|  |  | +		pipelines = null;
 | 
	
		
			
				|  |  | +		valves = null;
 | 
	
		
			
				|  |  | +		valves_spec = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		pipelines = await getPipelines(localStorage.token, selectedPipelinesUrlIdx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		if (pipelines.length > 0) {
 | 
	
		
			
				|  |  |  			selectedPipelineIdx = 0;
 | 
	
	
		
			
				|  | @@ -72,6 +81,12 @@
 | 
	
		
			
				|  |  |  	};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	onMount(async () => {
 | 
	
		
			
				|  |  | +		PIPELINES_LIST = await getPipelinesList(localStorage.token);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (PIPELINES_LIST.length > 0) {
 | 
	
		
			
				|  |  | +			selectedPipelinesUrlIdx = PIPELINES_LIST[0]['idx'];
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		setPipelines();
 | 
	
		
			
				|  |  |  	});
 | 
	
		
			
				|  |  |  </script>
 | 
	
	
		
			
				|  | @@ -83,95 +98,140 @@
 | 
	
		
			
				|  |  |  	}}
 | 
	
		
			
				|  |  |  >
 | 
	
		
			
				|  |  |  	<div class=" space-y-2 pr-1.5 overflow-y-scroll max-h-80 h-full">
 | 
	
		
			
				|  |  | -		{#if pipelines !== null && pipelines.length > 0}
 | 
	
		
			
				|  |  | +		{#if PIPELINES_LIST !== null}
 | 
	
		
			
				|  |  |  			<div class="flex w-full justify-between mb-2">
 | 
	
		
			
				|  |  |  				<div class=" self-center text-sm font-semibold">
 | 
	
		
			
				|  |  | -					{$i18n.t('Pipelines')}
 | 
	
		
			
				|  |  | +					{$i18n.t('Manage Pipelines')}
 | 
	
		
			
				|  |  |  				</div>
 | 
	
		
			
				|  |  |  			</div>
 | 
	
		
			
				|  |  | -			<div class="space-y-1">
 | 
	
		
			
				|  |  | -				{#if pipelines.length > 0}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			{#if PIPELINES_LIST.length > 0}
 | 
	
		
			
				|  |  | +				<div class="space-y-1">
 | 
	
		
			
				|  |  |  					<div class="flex gap-2">
 | 
	
		
			
				|  |  | -						<div class="flex-1 pb-1">
 | 
	
		
			
				|  |  | +						<div class="flex-1">
 | 
	
		
			
				|  |  |  							<select
 | 
	
		
			
				|  |  |  								class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
 | 
	
		
			
				|  |  | -								bind:value={selectedPipelineIdx}
 | 
	
		
			
				|  |  | -								placeholder={$i18n.t('Select a pipeline')}
 | 
	
		
			
				|  |  | +								bind:value={selectedPipelinesUrlIdx}
 | 
	
		
			
				|  |  | +								placeholder={$i18n.t('Select a pipeline url')}
 | 
	
		
			
				|  |  |  								on:change={async () => {
 | 
	
		
			
				|  |  |  									await tick();
 | 
	
		
			
				|  |  | -									await getValves(selectedPipelineIdx);
 | 
	
		
			
				|  |  | +									await setPipelines();
 | 
	
		
			
				|  |  |  								}}
 | 
	
		
			
				|  |  |  							>
 | 
	
		
			
				|  |  | -								{#each pipelines as pipeline, idx}
 | 
	
		
			
				|  |  | -									<option value={idx} class="bg-gray-100 dark:bg-gray-700"
 | 
	
		
			
				|  |  | -										>{pipeline.name} ({pipeline.pipeline.type ?? 'pipe'})</option
 | 
	
		
			
				|  |  | +								<option value="" selected disabled class="bg-gray-100 dark:bg-gray-700"
 | 
	
		
			
				|  |  | +									>{$i18n.t('Select a pipeline url')}</option
 | 
	
		
			
				|  |  | +								>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +								{#each PIPELINES_LIST as pipelines, idx}
 | 
	
		
			
				|  |  | +									<option value={pipelines.idx} class="bg-gray-100 dark:bg-gray-700"
 | 
	
		
			
				|  |  | +										>{pipelines.url}</option
 | 
	
		
			
				|  |  |  									>
 | 
	
		
			
				|  |  |  								{/each}
 | 
	
		
			
				|  |  |  							</select>
 | 
	
		
			
				|  |  |  						</div>
 | 
	
		
			
				|  |  |  					</div>
 | 
	
		
			
				|  |  | -				{/if}
 | 
	
		
			
				|  |  | +				</div>
 | 
	
		
			
				|  |  | +			{/if}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				<div class="text-sm font-medium">{$i18n.t('Valves')}</div>
 | 
	
		
			
				|  |  | +			<hr class=" dark:border-gray-800 my-3 w-full" />
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				<div class="space-y-1">
 | 
	
		
			
				|  |  | -					{#if pipelines[selectedPipelineIdx].pipeline.valves}
 | 
	
		
			
				|  |  | -						{#if valves}
 | 
	
		
			
				|  |  | -							{#each Object.keys(valves_spec.properties) as property, idx}
 | 
	
		
			
				|  |  | -								<div class=" py-0.5 w-full justify-between">
 | 
	
		
			
				|  |  | -									<div class="flex w-full justify-between">
 | 
	
		
			
				|  |  | -										<div class=" self-center text-xs font-medium">
 | 
	
		
			
				|  |  | -											{valves_spec.properties[property].title}
 | 
	
		
			
				|  |  | -										</div>
 | 
	
		
			
				|  |  | +			{#if pipelines !== null}
 | 
	
		
			
				|  |  | +				{#if pipelines.length > 0}
 | 
	
		
			
				|  |  | +					<div class="flex w-full justify-between mb-2">
 | 
	
		
			
				|  |  | +						<div class=" self-center text-sm font-semibold">
 | 
	
		
			
				|  |  | +							{$i18n.t('Pipelines Valves')}
 | 
	
		
			
				|  |  | +						</div>
 | 
	
		
			
				|  |  | +					</div>
 | 
	
		
			
				|  |  | +					<div class="space-y-1">
 | 
	
		
			
				|  |  | +						{#if pipelines.length > 0}
 | 
	
		
			
				|  |  | +							<div class="flex gap-2">
 | 
	
		
			
				|  |  | +								<div class="flex-1 pb-1">
 | 
	
		
			
				|  |  | +									<select
 | 
	
		
			
				|  |  | +										class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
 | 
	
		
			
				|  |  | +										bind:value={selectedPipelineIdx}
 | 
	
		
			
				|  |  | +										placeholder={$i18n.t('Select a pipeline')}
 | 
	
		
			
				|  |  | +										on:change={async () => {
 | 
	
		
			
				|  |  | +											await tick();
 | 
	
		
			
				|  |  | +											await getValves(selectedPipelineIdx);
 | 
	
		
			
				|  |  | +										}}
 | 
	
		
			
				|  |  | +									>
 | 
	
		
			
				|  |  | +										{#each pipelines as pipeline, idx}
 | 
	
		
			
				|  |  | +											<option value={idx} class="bg-gray-100 dark:bg-gray-700"
 | 
	
		
			
				|  |  | +												>{pipeline.name} ({pipeline.pipeline.type ?? 'pipe'})</option
 | 
	
		
			
				|  |  | +											>
 | 
	
		
			
				|  |  | +										{/each}
 | 
	
		
			
				|  |  | +									</select>
 | 
	
		
			
				|  |  | +								</div>
 | 
	
		
			
				|  |  | +							</div>
 | 
	
		
			
				|  |  | +						{/if}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -										<button
 | 
	
		
			
				|  |  | -											class="p-1 px-3 text-xs flex rounded transition"
 | 
	
		
			
				|  |  | -											type="button"
 | 
	
		
			
				|  |  | -											on:click={() => {
 | 
	
		
			
				|  |  | -												valves[property] = (valves[property] ?? null) === null ? '' : null;
 | 
	
		
			
				|  |  | -											}}
 | 
	
		
			
				|  |  | -										>
 | 
	
		
			
				|  |  | -											{#if (valves[property] ?? null) === null}
 | 
	
		
			
				|  |  | -												<span class="ml-2 self-center"> {$i18n.t('None')} </span>
 | 
	
		
			
				|  |  | -											{:else}
 | 
	
		
			
				|  |  | -												<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
 | 
	
		
			
				|  |  | -											{/if}
 | 
	
		
			
				|  |  | -										</button>
 | 
	
		
			
				|  |  | -									</div>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -									{#if (valves[property] ?? null) !== null}
 | 
	
		
			
				|  |  | -										<div class="flex mt-0.5 space-x-2">
 | 
	
		
			
				|  |  | -											<div class=" flex-1">
 | 
	
		
			
				|  |  | -												<input
 | 
	
		
			
				|  |  | -													class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
 | 
	
		
			
				|  |  | -													type="text"
 | 
	
		
			
				|  |  | -													placeholder={valves_spec.properties[property].title}
 | 
	
		
			
				|  |  | -													bind:value={valves[property]}
 | 
	
		
			
				|  |  | -													autocomplete="off"
 | 
	
		
			
				|  |  | -												/>
 | 
	
		
			
				|  |  | +						<div class="space-y-1">
 | 
	
		
			
				|  |  | +							{#if pipelines[selectedPipelineIdx].pipeline.valves}
 | 
	
		
			
				|  |  | +								{#if valves}
 | 
	
		
			
				|  |  | +									{#each Object.keys(valves_spec.properties) as property, idx}
 | 
	
		
			
				|  |  | +										<div class=" py-0.5 w-full justify-between">
 | 
	
		
			
				|  |  | +											<div class="flex w-full justify-between">
 | 
	
		
			
				|  |  | +												<div class=" self-center text-xs font-medium">
 | 
	
		
			
				|  |  | +													{valves_spec.properties[property].title}
 | 
	
		
			
				|  |  | +												</div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +												<button
 | 
	
		
			
				|  |  | +													class="p-1 px-3 text-xs flex rounded transition"
 | 
	
		
			
				|  |  | +													type="button"
 | 
	
		
			
				|  |  | +													on:click={() => {
 | 
	
		
			
				|  |  | +														valves[property] = (valves[property] ?? null) === null ? '' : null;
 | 
	
		
			
				|  |  | +													}}
 | 
	
		
			
				|  |  | +												>
 | 
	
		
			
				|  |  | +													{#if (valves[property] ?? null) === null}
 | 
	
		
			
				|  |  | +														<span class="ml-2 self-center"> {$i18n.t('None')} </span>
 | 
	
		
			
				|  |  | +													{:else}
 | 
	
		
			
				|  |  | +														<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
 | 
	
		
			
				|  |  | +													{/if}
 | 
	
		
			
				|  |  | +												</button>
 | 
	
		
			
				|  |  |  											</div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +											{#if (valves[property] ?? null) !== null}
 | 
	
		
			
				|  |  | +												<div class="flex mt-0.5 space-x-2">
 | 
	
		
			
				|  |  | +													<div class=" flex-1">
 | 
	
		
			
				|  |  | +														<input
 | 
	
		
			
				|  |  | +															class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
 | 
	
		
			
				|  |  | +															type="text"
 | 
	
		
			
				|  |  | +															placeholder={valves_spec.properties[property].title}
 | 
	
		
			
				|  |  | +															bind:value={valves[property]}
 | 
	
		
			
				|  |  | +															autocomplete="off"
 | 
	
		
			
				|  |  | +														/>
 | 
	
		
			
				|  |  | +													</div>
 | 
	
		
			
				|  |  | +												</div>
 | 
	
		
			
				|  |  | +											{/if}
 | 
	
		
			
				|  |  |  										</div>
 | 
	
		
			
				|  |  | -									{/if}
 | 
	
		
			
				|  |  | -								</div>
 | 
	
		
			
				|  |  | -							{/each}
 | 
	
		
			
				|  |  | -						{:else}
 | 
	
		
			
				|  |  | -							<Spinner className="size-5" />
 | 
	
		
			
				|  |  | -						{/if}
 | 
	
		
			
				|  |  | -					{:else}
 | 
	
		
			
				|  |  | -						<div>No valves</div>
 | 
	
		
			
				|  |  | -					{/if}
 | 
	
		
			
				|  |  | +									{/each}
 | 
	
		
			
				|  |  | +								{:else}
 | 
	
		
			
				|  |  | +									<Spinner className="size-5" />
 | 
	
		
			
				|  |  | +								{/if}
 | 
	
		
			
				|  |  | +							{:else}
 | 
	
		
			
				|  |  | +								<div>No valves</div>
 | 
	
		
			
				|  |  | +							{/if}
 | 
	
		
			
				|  |  | +						</div>
 | 
	
		
			
				|  |  | +					</div>
 | 
	
		
			
				|  |  | +				{:else if pipelines.length === 0}
 | 
	
		
			
				|  |  | +					<div>Pipelines Not Detected</div>
 | 
	
		
			
				|  |  | +				{/if}
 | 
	
		
			
				|  |  | +			{:else}
 | 
	
		
			
				|  |  | +				<div class="flex justify-center">
 | 
	
		
			
				|  |  | +					<div class="my-auto">
 | 
	
		
			
				|  |  | +						<Spinner className="size-4" />
 | 
	
		
			
				|  |  | +					</div>
 | 
	
		
			
				|  |  |  				</div>
 | 
	
		
			
				|  |  | -			</div>
 | 
	
		
			
				|  |  | -		{:else if pipelines !== null && pipelines.length === 0}
 | 
	
		
			
				|  |  | -			<div>Pipelines Not Detected</div>
 | 
	
		
			
				|  |  | +			{/if}
 | 
	
		
			
				|  |  |  		{:else}
 | 
	
		
			
				|  |  | -			<div class="flex h-full justify-center">
 | 
	
		
			
				|  |  | +			<div class="flex justify-center h-full">
 | 
	
		
			
				|  |  |  				<div class="my-auto">
 | 
	
		
			
				|  |  |  					<Spinner className="size-6" />
 | 
	
		
			
				|  |  |  				</div>
 | 
	
		
			
				|  |  |  			</div>
 | 
	
		
			
				|  |  |  		{/if}
 | 
	
		
			
				|  |  |  	</div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	<div class="flex justify-end pt-3 text-sm font-medium">
 | 
	
		
			
				|  |  |  		<button
 | 
	
		
			
				|  |  |  			class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
 |