-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: VariablesTable
, VariablesDelete
, filters, bulk and count routes
#1296
Changes from all commits
884f56f
14fe90e
38321d9
c1fc718
e9c3e19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<template> | ||
<p-button v-if="variableIds.length > 0" danger icon="TrashIcon" @click="open" /> | ||
<ConfirmDeleteModal | ||
v-model:showModal="showModal" | ||
:name="localization.info.selectedVariables" | ||
:label="localization.info.variables" | ||
@delete="deleteVariables(variableIds)" | ||
/> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { showToast } from '@prefecthq/prefect-design' | ||
import { computed } from 'vue' | ||
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue' | ||
import { useShowModal, useWorkspaceApi } from '@/compositions' | ||
import { localization } from '@/localization' | ||
import { toPluralString } from '@/utilities' | ||
|
||
defineProps<{ | ||
variableIds: string[], | ||
}>() | ||
|
||
const emit = defineEmits<{ | ||
(event: 'delete'): string[], | ||
}>() | ||
|
||
const { showModal, open, close } = useShowModal() | ||
|
||
const api = useWorkspaceApi() | ||
|
||
const deleteVariables = async (variableIds: string[]): Promise<void> => { | ||
try { | ||
const variableDeletePromises = variableIds.map(api.variables.deleteVariable) | ||
await Promise.all(variableDeletePromises) | ||
|
||
const successMessage = localization.success.delete(`${variableIds.length} ${toPluralString(localization.info.variable, variableIds.length)}`) | ||
showToast(successMessage, 'success') | ||
emit('delete') | ||
} catch (error) { | ||
showToast(localization.error.delete(localization.info.variables), 'error') | ||
} finally { | ||
close() | ||
} | ||
} | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
<template> | ||
<div class="variables-table"> | ||
<p-layout-table sticky> | ||
<template #header-start> | ||
<div class="variables-table__header-start"> | ||
<ResultsCount v-if="selectedVariables.length == 0" :label="localization.info.variable" :count="variablesCount" /> | ||
<SelectedCount v-else :count="selectedVariables.length" /> | ||
|
||
<FlowsDeleteButton v-if="can.delete.variable" :selected="selectedVariables" @delete="deleteVariables" /> | ||
</div> | ||
</template> | ||
|
||
<template #header-end> | ||
<div class="variables-table__header-end"> | ||
<SearchInput v-model="variableLike" :placeholder="localization.info.variablesSearch" :label="localization.info.variablesSearch" /> | ||
<p-select v-model="filter.sort" :options="variableSortOptions" /> | ||
<p-tags-input v-model="filter.variables.tags.name" :empty-message="localization.info.tags" class="variables-table__tags" /> | ||
</div> | ||
</template> | ||
|
||
<p-table :data="variables" :columns="columns"> | ||
<template #selection-heading> | ||
<p-checkbox v-model="model" @update:model-value="selectAllVariables" /> | ||
</template> | ||
|
||
<template #selection="{ row }"> | ||
<p-checkbox v-model="selectedVariables" :value="row.id" /> | ||
</template> | ||
|
||
<template #name="{ row }"> | ||
<span>{{ row.name }}</span> | ||
</template> | ||
|
||
<template #updated="{ row }"> | ||
{{ formatDateTimeNumeric(row.updated) }} | ||
</template> | ||
|
||
<template #action-heading> | ||
<span /> | ||
</template> | ||
|
||
<template #action="{ row }"> | ||
<div class="variables-table__action"> | ||
<VariableMenu :variable="row" size="xs" @delete="refresh" /> | ||
</div> | ||
</template> | ||
|
||
<template #empty-state> | ||
<PEmptyResults> | ||
<template #message> | ||
{{ localization.info.noVariables }} | ||
</template> | ||
<template v-if="isCustomFilter" #actions> | ||
<p-button size="sm" secondary @click="clear"> | ||
Clear Filters | ||
</p-button> | ||
</template> | ||
</PEmptyResults> | ||
</template> | ||
</p-table> | ||
|
||
<template #footer-end> | ||
<p-pager v-if="variables.length" v-model:page="offset" :pages="variablesCount" /> | ||
</template> | ||
</p-layout-table> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { PTable, PEmptyResults, CheckboxModel } from '@prefecthq/prefect-design' | ||
import { useDebouncedRef, useSubscription } from '@prefecthq/vue-compositions' | ||
import { computed, ref } from 'vue' | ||
import { FlowsDeleteButton, VariableMenu, ResultsCount, SearchInput, SelectedCount } from '@/components' | ||
import { useCan, useVariablesFilter, useWorkspaceApi } from '@/compositions' | ||
import { localization } from '@/localization' | ||
import { VariablesFilter } from '@/models/Filters' | ||
import { variableSortOptions } from '@/types' | ||
import { formatDateTimeNumeric } from '@/utilities/dates' | ||
|
||
const props = defineProps<{ | ||
filter?: VariablesFilter, | ||
}>() | ||
|
||
const api = useWorkspaceApi() | ||
const can = useCan() | ||
|
||
const variableLike = ref<string>() | ||
const variableLikeDebounced = useDebouncedRef(variableLike, 1000) | ||
const offset = ref(0) | ||
|
||
const { filter, isCustomFilter, clear } = useVariablesFilter({ | ||
...props.filter, | ||
variables: { | ||
...props.filter?.variables, | ||
nameLike: variableLikeDebounced, | ||
valueLike: variableLikeDebounced, | ||
}, | ||
offset, | ||
}) | ||
|
||
const columns = [ | ||
{ | ||
label: 'selection', | ||
width: '20px', | ||
visible: can.delete.variable, | ||
}, | ||
{ | ||
property: 'name', | ||
label: 'Name', | ||
width: '125px', | ||
}, | ||
{ | ||
property: 'value', | ||
label: 'Value', | ||
width: '125px', | ||
}, | ||
{ | ||
property: 'updated', | ||
label: 'Updated', | ||
width: '125px', | ||
}, | ||
{ | ||
label: 'Action', | ||
width: '42px', | ||
}, | ||
] | ||
|
||
const selectedVariables = ref<string[]>([]) | ||
const selectAllVariables = (allVariablesSelected: CheckboxModel): string[] => { | ||
if (allVariablesSelected) { | ||
return selectedVariables.value = [...variables.value.map(variable => variable.id)] | ||
} | ||
return selectedVariables.value = [] | ||
} | ||
|
||
const model = computed({ | ||
get() { | ||
return selectedVariables.value.length === variables.value.length | ||
}, | ||
set(value: boolean) { | ||
selectAllVariables(value) | ||
}, | ||
}) | ||
Comment on lines
+128
to
+143
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should make a select all component for this. Takes an array v-model and an array of all the possible values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yea good thought, we're doing this in a few places. I'll open a ticket 👍🏻 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
const variablesSubscription = useSubscription(api.variables.getVariables, [filter]) | ||
const variables = computed(() => variablesSubscription.response ?? []) | ||
|
||
const variablesCountSubscription = useSubscription(api.variables.getVariablesCount, [filter]) | ||
const variablesCount = computed(() => variablesCountSubscription.response) | ||
|
||
function refresh(): void { | ||
variablesSubscription.refresh() | ||
variablesCountSubscription.refresh() | ||
} | ||
|
||
const emit = defineEmits<{ | ||
(event: 'delete'): void, | ||
}>() | ||
|
||
const deleteVariables = (): void => { | ||
selectedVariables.value = [] | ||
refresh() | ||
emit('delete') | ||
} | ||
</script> | ||
|
||
<style> | ||
.variables-table__header-start { @apply | ||
grow | ||
whitespace-nowrap | ||
} | ||
|
||
.variables-table__header-end { @apply | ||
flex | ||
flex-wrap | ||
pl-2 | ||
ml-auto | ||
shrink | ||
gap-2 | ||
} | ||
|
||
.variables-table__tags { | ||
min-width: 128px; | ||
} | ||
|
||
.variables-table__action { @apply | ||
text-right | ||
} | ||
</style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this feature is being actively built. Any chance we can get an api endpoint for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jakekaplan and i talked about this yesterday (great minds etc) - we can but we don't really need it since there's a fairly low cap on the number of variables one can create