move condition to ts
This commit is contained in:
parent
9d24fc01b4
commit
5e14c232d7
3 changed files with 152 additions and 147 deletions
12
ui/@types/conditions.d.ts
vendored
Normal file
12
ui/@types/conditions.d.ts
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
export type ConditionItem = {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
filter: string
|
||||||
|
cli: string
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ImportedConditionItem = ConditionItem & {
|
||||||
|
_type: string
|
||||||
|
_version: string
|
||||||
|
}
|
||||||
|
|
@ -206,77 +206,37 @@
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
const emitter = defineEmits(['cancel', 'submit'])
|
|
||||||
import { decode } from '~/utils/importer'
|
import { decode } from '~/utils/importer'
|
||||||
|
import type { ConditionItem, ImportedConditionItem } from '~/@types/conditions'
|
||||||
|
|
||||||
const props = defineProps({
|
const emitter = defineEmits<{
|
||||||
reference: {
|
(e: 'cancel'): void
|
||||||
type: String,
|
(e: 'submit', payload: { reference: string | null | undefined, item: ConditionItem }): void
|
||||||
required: false,
|
}>()
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
addInProgress: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const test_data = ref({ show: false, url: '', data: { status: null, data: {} }, in_progress: false })
|
const props = defineProps<{
|
||||||
|
reference?: string | null
|
||||||
|
item: ConditionItem
|
||||||
|
addInProgress?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const toast = useNotification()
|
const toast = useNotification()
|
||||||
const box = useConfirm()
|
|
||||||
const form = reactive(JSON.parse(JSON.stringify(props.item)))
|
|
||||||
const import_string = ref('')
|
|
||||||
const showImport = useStorage('showImport', false)
|
const showImport = useStorage('showImport', false)
|
||||||
|
const box = useConfirm()
|
||||||
|
|
||||||
const run_test = async () => {
|
const form = reactive<ConditionItem>(JSON.parse(JSON.stringify(props.item)))
|
||||||
if (!test_data.value.url) {
|
const import_string = ref('')
|
||||||
toast.error('The URL is required for testing.', { force: true })
|
const test_data = ref<{
|
||||||
return
|
show: boolean,
|
||||||
}
|
url: string,
|
||||||
|
in_progress: boolean,
|
||||||
|
data: { status: boolean | null, data: Record<string, any> }
|
||||||
|
}>({ show: false, url: '', in_progress: false, data: { status: null, data: {} } })
|
||||||
|
|
||||||
try {
|
const checkInfo = async (): Promise<void> => {
|
||||||
new URL(test_data.value.url)
|
const required: (keyof ConditionItem)[] = ['name', 'filter', 'cli']
|
||||||
} catch (e) {
|
|
||||||
toast.error('The URL is invalid.', { force: true })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
test_data.value.in_progress = true
|
|
||||||
test_data.value.data.status = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await request('/api/conditions/test', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({
|
|
||||||
url: test_data.value.url,
|
|
||||||
condition: form.filter,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
const json = await response.json()
|
|
||||||
if (!response.ok) {
|
|
||||||
toast.error(json.message || json.error || 'Unknown error', { force: true })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
test_data.value.data = json
|
|
||||||
} catch (e) {
|
|
||||||
toast.error(`Failed to test condition. ${error.message}`)
|
|
||||||
} finally {
|
|
||||||
test_data.value.in_progress = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkInfo = async () => {
|
|
||||||
const required = ['name', 'filter', 'cli']
|
|
||||||
|
|
||||||
for (const key of required) {
|
for (const key of required) {
|
||||||
if (!form[key]) {
|
if (!form[key]) {
|
||||||
|
|
@ -285,15 +245,15 @@ const checkInfo = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (form?.cli && '' !== form.cli) {
|
if (form.cli && '' !== form.cli.trim()) {
|
||||||
const options = await convertOptions(form.cli)
|
const options = await convertOptions(form.cli)
|
||||||
if (null === options) {
|
if (options === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
form.cli = form.cli.trim()
|
form.cli = form.cli.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
let copy = JSON.parse(JSON.stringify(form))
|
const copy: ConditionItem = JSON.parse(JSON.stringify(form))
|
||||||
|
|
||||||
for (const key in copy) {
|
for (const key in copy) {
|
||||||
if (typeof copy[key] !== 'string') {
|
if (typeof copy[key] !== 'string') {
|
||||||
|
|
@ -305,32 +265,68 @@ const checkInfo = async () => {
|
||||||
emitter('submit', { reference: toRaw(props.reference), item: toRaw(copy) })
|
emitter('submit', { reference: toRaw(props.reference), item: toRaw(copy) })
|
||||||
}
|
}
|
||||||
|
|
||||||
const convertOptions = async args => {
|
const convertOptions = async (args: string): Promise<any | null> => {
|
||||||
try {
|
try {
|
||||||
const response = await convertCliOptions(args)
|
const response = await convertCliOptions(args)
|
||||||
return response.opts
|
return response.opts
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
toast.error(e.message)
|
toast.error(e.message)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const importItem = async () => {
|
const run_test = async (): Promise<void> => {
|
||||||
let val = import_string.value.trim()
|
if (!test_data.value.url) {
|
||||||
|
toast.error('The URL is required for testing.', { force: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new URL(test_data.value.url)
|
||||||
|
} catch {
|
||||||
|
toast.error('The URL is invalid.', { force: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
test_data.value.in_progress = true
|
||||||
|
test_data.value.data.status = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await request('/api/conditions/test', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ url: test_data.value.url, condition: form.filter })
|
||||||
|
})
|
||||||
|
|
||||||
|
const json = await response.json()
|
||||||
|
if (!response.ok) {
|
||||||
|
toast.error(json.message || json.error || 'Unknown error', { force: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
test_data.value.data = json
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(`Failed to test condition. ${error.message}`)
|
||||||
|
} finally {
|
||||||
|
test_data.value.in_progress = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const importItem = async (): Promise<void> => {
|
||||||
|
const val = import_string.value.trim()
|
||||||
if (!val) {
|
if (!val) {
|
||||||
toast.error('The import string is required.')
|
toast.error('The import string is required.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const item = decode(val)
|
const item = decode(val) as ImportedConditionItem
|
||||||
|
|
||||||
if (!item?._type || 'condition' !== item._type) {
|
if (!item?._type || item._type !== 'condition') {
|
||||||
toast.error(`Invalid import string. Expected type 'condition', got '${item._type ?? 'unknown'}'.`)
|
toast.error(`Invalid import string. Expected type 'condition', got '${item._type ?? 'unknown'}'.`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((form.filter || form.cli) && false === box.confirm('Overwrite the current form fields?', true)) {
|
if ((form.filter || form.cli) && !box.confirm('Overwrite the current form fields?', true)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,14 +344,14 @@ const importItem = async () => {
|
||||||
|
|
||||||
import_string.value = ''
|
import_string.value = ''
|
||||||
showImport.value = false
|
showImport.value = false
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
toast.error(`Failed to parse import string. ${e.message}`)
|
toast.error(`Failed to parse import string. ${e.message}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const show_data = () => {
|
const show_data = (): string => {
|
||||||
if (!test_data.value.data?.data || !Object.keys(test_data.value.data?.data).length) {
|
if (!test_data.value.data?.data || Object.keys(test_data.value.data.data).length === 0) {
|
||||||
return 'No data to show.'
|
return 'No data to show.'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<p class="control">
|
<p class="control">
|
||||||
<button class="button is-info" @click="reloadContent" :class="{ 'is-loading': isLoading }"
|
<button class="button is-info" @click="reloadContent(false)" :class="{ 'is-loading': isLoading }"
|
||||||
:disabled="!socket.isConnected || isLoading" v-if="items && items.length > 0">
|
:disabled="!socket.isConnected || isLoading" v-if="items && items.length > 0">
|
||||||
<span class="icon"><i class="fas fa-refresh" /></span>
|
<span class="icon"><i class="fas fa-refresh" /></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -30,8 +30,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column is-12" v-if="toggleForm">
|
<div class="column is-12" v-if="toggleForm">
|
||||||
<ConditionForm :addInProgress="addInProgress" :reference="itemRef" :item="item" @cancel="resetForm(true)"
|
<ConditionForm :addInProgress="addInProgress" :reference="itemRef" :item="item as ConditionItem"
|
||||||
@submit="updateItem" />
|
@cancel="resetForm(true)" @submit="updateItem" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column is-12" v-if="!toggleForm">
|
<div class="column is-12" v-if="!toggleForm">
|
||||||
|
|
@ -114,18 +114,19 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { request } from '~/utils/index'
|
import { request } from '~/utils/index'
|
||||||
import { encode } from '~/utils/importer'
|
import { encode } from '~/utils/importer'
|
||||||
|
import type { ConditionItem, ImportedConditionItem } from '~/@types/conditions'
|
||||||
|
|
||||||
const toast = useNotification()
|
const toast = useNotification()
|
||||||
const config = useConfigStore()
|
const config = useConfigStore()
|
||||||
const socket = useSocketStore()
|
const socket = useSocketStore()
|
||||||
const box = useConfirm()
|
const box = useConfirm()
|
||||||
|
|
||||||
const items = ref([])
|
const items = ref<ConditionItem[]>([])
|
||||||
const item = ref({})
|
const item = ref<Partial<ConditionItem>>({})
|
||||||
const itemRef = ref("")
|
const itemRef = ref<string | null | undefined>("")
|
||||||
const toggleForm = ref(false)
|
const toggleForm = ref(false)
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const initialLoad = ref(true)
|
const initialLoad = ref(true)
|
||||||
|
|
@ -146,15 +147,15 @@ watch(() => socket.isConnected, async () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const reloadContent = async (fromMounted = false) => {
|
|
||||||
|
const reloadContent = async (fromMounted = false): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
const response = await request("/api/conditions")
|
const response = await request('/api/conditions')
|
||||||
|
|
||||||
if (fromMounted && !response.ok) {
|
if (fromMounted && !response.ok) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
if (data.length < 1) {
|
if (data.length < 1) {
|
||||||
return
|
return
|
||||||
|
|
@ -162,17 +163,16 @@ const reloadContent = async (fromMounted = false) => {
|
||||||
|
|
||||||
items.value = data
|
items.value = data
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (fromMounted) {
|
if (!fromMounted) {
|
||||||
return
|
console.error(e)
|
||||||
|
toast.error('Failed to fetch page content.')
|
||||||
}
|
}
|
||||||
console.error(e)
|
|
||||||
toast.error("Failed to fetch page content.")
|
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = (closeForm = false) => {
|
const resetForm = (closeForm = false): void => {
|
||||||
item.value = {}
|
item.value = {}
|
||||||
itemRef.value = null
|
itemRef.value = null
|
||||||
addInProgress.value = false
|
addInProgress.value = false
|
||||||
|
|
@ -181,30 +181,29 @@ const resetForm = (closeForm = false) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateItems = async items => {
|
const updateItems = async (newItems: ConditionItem[]): Promise<boolean> => {
|
||||||
let data
|
let data: any
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addInProgress.value = true
|
addInProgress.value = true
|
||||||
|
|
||||||
const local_items = []
|
const validItems = newItems.map(({ id, name, filter, cli }) => {
|
||||||
for (const item of items) {
|
|
||||||
const { id, name, filter, cli } = item
|
|
||||||
if (!name || !filter || !cli) {
|
if (!name || !filter || !cli) {
|
||||||
toast.error("Name, filter and cli are required.")
|
toast.error('Name, filter and cli are required.')
|
||||||
return false
|
throw new Error('Missing fields')
|
||||||
}
|
}
|
||||||
local_items.push({ id, name, filter, cli })
|
return { id, name, filter, cli }
|
||||||
}
|
|
||||||
|
|
||||||
const response = await request("/api/conditions", {
|
|
||||||
method: "PUT",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(local_items),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
data = await response.json()
|
const response = await request('/api/conditions', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(validItems),
|
||||||
|
})
|
||||||
|
|
||||||
if (200 !== response.status) {
|
data = await response.json() as ConditionItem[]
|
||||||
|
|
||||||
|
if (response.status !== 200) {
|
||||||
toast.error(`Failed to update items. ${data.error}`)
|
toast.error(`Failed to update items. ${data.error}`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -212,44 +211,46 @@ const updateItems = async items => {
|
||||||
items.value = data
|
items.value = data
|
||||||
resetForm(true)
|
resetForm(true)
|
||||||
return true
|
return true
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
toast.error(`Failed to update items. ${data?.error}. ${e.message}`)
|
toast.error(`Failed to update items. ${data?.error ?? ''} ${e.message}`)
|
||||||
} finally {
|
} finally {
|
||||||
addInProgress.value = false
|
addInProgress.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteItem = async (item) => {
|
const deleteItem = async (cond: ConditionItem): Promise<void> => {
|
||||||
if (true !== box.confirm(`Delete '${item.name}'?`, true)) {
|
if (!box.confirm(`Delete '${cond.name}'?`, true)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = items.value.findIndex((t) => t?.id === item.id)
|
const index = items.value.findIndex(t => t?.id === cond.id)
|
||||||
if (index > -1) {
|
if (-1 === index) {
|
||||||
items.value.splice(index, 1)
|
toast.error('Item not found.')
|
||||||
} else {
|
|
||||||
toast.error("Item not found.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items.value.splice(index, 1)
|
||||||
const status = await updateItems(items.value)
|
const status = await updateItems(items.value)
|
||||||
|
if (status) {
|
||||||
if (!status) {
|
toast.success('Item deleted.')
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success("Item deleted.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateItem = async ({ reference, item }) => {
|
const updateItem = async ({ reference, item: updatedItem, }: {
|
||||||
item = cleanObject(item, remove_keys)
|
reference: string | null | undefined,
|
||||||
|
item: ConditionItem
|
||||||
|
}): Promise<void> => {
|
||||||
|
updatedItem = cleanObject(updatedItem, remove_keys)
|
||||||
|
|
||||||
if (reference) {
|
if (reference) {
|
||||||
const index = items.value.findIndex(t => t?.id === reference)
|
const index = items.value.findIndex(t => t?.id === reference)
|
||||||
if (index > -1) {
|
if (index !== -1) {
|
||||||
items.value[index] = item
|
items.value[index] = updatedItem
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
items.value.push(item)
|
items.value.push(updatedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = await updateItems(items.value)
|
const status = await updateItems(items.value)
|
||||||
|
|
@ -257,36 +258,32 @@ const updateItem = async ({ reference, item }) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success(`Item ${reference ? "updated" : "added"}.`)
|
toast.success(`Item ${reference ? 'updated' : 'added'}.`)
|
||||||
resetForm(true)
|
resetForm(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const editItem = _item => {
|
const editItem = (_item: ConditionItem): void => {
|
||||||
item.value = _item
|
item.value = { ..._item }
|
||||||
itemRef.value = _item.id
|
itemRef.value = _item.id
|
||||||
toggleForm.value = true
|
toggleForm.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => (socket.isConnected ? await reloadContent(true) : ""))
|
const exportItem = (cond: ConditionItem): void => {
|
||||||
|
const clone: Partial<ImportedConditionItem> = JSON.parse(JSON.stringify(cond))
|
||||||
|
delete clone.id
|
||||||
|
|
||||||
const exportItem = item => {
|
const userData: ImportedConditionItem = {
|
||||||
let data = JSON.parse(JSON.stringify(item))
|
...Object.fromEntries(Object.entries(clone).filter(([_, v]) => !!v)),
|
||||||
if ("id" in data) {
|
_type: 'condition',
|
||||||
delete data['id']
|
_version: '1.0',
|
||||||
}
|
} as ImportedConditionItem
|
||||||
|
|
||||||
let userData = {}
|
copyText(encode(userData))
|
||||||
|
|
||||||
for (const key of Object.keys(data)) {
|
|
||||||
if (!data[key]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
userData[key] = data[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
userData['_type'] = 'condition'
|
|
||||||
userData['_version'] = '1.0'
|
|
||||||
|
|
||||||
return copyText(encode(userData))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (socket.isConnected) {
|
||||||
|
await reloadContent(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue