diff --git a/src/lib/components/filters/index.ts b/src/lib/components/filters/index.ts
index b2747057b..2aeeebec2 100644
--- a/src/lib/components/filters/index.ts
+++ b/src/lib/components/filters/index.ts
@@ -3,4 +3,5 @@ export { default as TagList } from './tagList.svelte';
export { default as FilterMenu } from './menu.svelte';
export { default as FilterSubMenu } from './subMenu.svelte';
export { default as CustomFilters } from './customFilters.svelte';
+export { default as QuickFilters } from './quickFilters.svelte';
export { hasPageQueries, queryParamToMap, queries } from '$lib/components/filters/store';
diff --git a/src/lib/components/filters/quickFilters.svelte b/src/lib/components/filters/quickFilters.svelte
new file mode 100644
index 000000000..7cdff80a7
--- /dev/null
+++ b/src/lib/components/filters/quickFilters.svelte
@@ -0,0 +1,67 @@
+
+
+
diff --git a/src/lib/components/filters/quickFilters.ts b/src/lib/components/filters/quickFilters.ts
new file mode 100644
index 000000000..0bbe84fe3
--- /dev/null
+++ b/src/lib/components/filters/quickFilters.ts
@@ -0,0 +1,83 @@
+import type { Column } from '$lib/helpers/types';
+import { get } from 'svelte/store';
+import { addFilter, queries, tags, ValidOperators } from './store';
+import { Submit, trackEvent } from '$lib/actions/analytics';
+
+export type FilterData = {
+ title: string;
+ id: string;
+ array: boolean;
+ show: boolean;
+ tag: string;
+ operator: ValidOperators;
+ options: { value: string; label: string; checked: boolean }[];
+};
+
+export function buildFilterCol(col: Column, customOperator = null): FilterData {
+ return {
+ title: col.title,
+ id: col.id,
+ show: false,
+ array: col?.array,
+ tag: null,
+ operator: customOperator ?? ValidOperators.Equal,
+ options: col?.elements?.map((element) => {
+ return {
+ value: (element?.value ?? element) as string,
+ label: (element?.label ?? element) as string,
+ checked: false
+ };
+ })
+ };
+}
+
+export function addFilterAndApply(
+ colId: string,
+ colTitle: string,
+ operator: ValidOperators,
+ value: string,
+ arrayValues: string[] = [],
+ columns: Column[],
+ analyticsSource: string
+) {
+ const tagList = get(tags).filter((tag) => tag.tag.includes(colTitle));
+ tagList.forEach((tag) => queries.removeFilter(tag));
+ if (value || arrayValues?.length) {
+ if (colId === 'sourceSize' || colId === 'buildSize') {
+ addSizeFilter(value, colId, columns);
+ } else if (colId === 'statusCode') {
+ addStatusCodeFilter(value, colId, columns);
+ } else if (colId === '$createdAt' || colId === '$updatedAt' || colId === 'buildDuration') {
+ addDateFilter(value, colId, columns);
+ } else {
+ addFilter(columns, colId, operator, value, arrayValues);
+ }
+ }
+ queries.apply();
+ trackEvent(Submit.ApplyQuickFilter, {
+ source: analyticsSource,
+ column: colId,
+ value: value || arrayValues.join(', ')
+ });
+}
+
+export function resetOptions(filter: FilterData) {
+ filter.options.forEach((option) => {
+ option.checked = false;
+ });
+}
+
+export function addStatusCodeFilter(value: string, colId: string, columns: Column[]) {
+ addFilter(columns, colId, ValidOperators.LessThanOrEqual, parseInt(value));
+ addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, parseInt(value) - 99);
+}
+export function addDateFilter(value: string, colId: string, columns: Column[]) {
+ const now = new Date();
+ const isoValue = new Date(now.getTime() - parseInt(value));
+ addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, isoValue.toISOString());
+ addFilter(columns, colId, ValidOperators.LessThanOrEqual, now.toISOString());
+}
+
+export function addSizeFilter(value: string, colId: string, columns: Column[]) {
+ addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, value);
+}
diff --git a/src/lib/components/filters/setFilters.ts b/src/lib/components/filters/setFilters.ts
new file mode 100644
index 000000000..07611409b
--- /dev/null
+++ b/src/lib/components/filters/setFilters.ts
@@ -0,0 +1,133 @@
+import type { Column } from '$lib/helpers/types';
+import { resetOptions, type FilterData } from './quickFilters';
+import type { TagValue } from './store';
+
+export function setFiltersOnNavigate(
+ tags: TagValue[],
+ filterCols: FilterData[],
+ $columns: Column[]
+) {
+ if (!tags?.length) {
+ filterCols.forEach((filter) => {
+ resetOptions(filter);
+ });
+ } else {
+ filterCols.forEach((filter) => {
+ if (filter.id === 'buildDuration') {
+ setTimeFilter(tags, filter, $columns);
+ } else if (filter.id.includes('size')) {
+ setSizeFilter(tags, filter, $columns);
+ } else if (filter.id === 'statusCode') {
+ setStatusCodeFilter(tags, filter, $columns);
+ } else if (filter.id === '$createdAt' || filter.id === '$updatedAt') {
+ setDateFilter(tags, filter, $columns);
+ } else {
+ setFilterData(filter, tags);
+ }
+ });
+
+ // Reasinging the filters to trigger reactivity
+ filterCols = filterCols;
+ }
+}
+
+export function setFilterData(filter: FilterData, list: TagValue[]) {
+ const tagData = list.find((tag) => tag.tag.includes(`**${filter.title}**`));
+ if (tagData) {
+ filter.tag = tagData.tag;
+ if (Array.isArray(tagData.value) && tagData.value?.length) {
+ const values = tagData.value as string[];
+ filter.options.forEach((option) => {
+ option.checked = values.includes(option.value);
+ });
+ }
+ } else {
+ filter.tag = null;
+ resetOptions(filter);
+ }
+}
+
+export function setTimeFilter(localTags: TagValue[], filter: FilterData, columns: Column[]) {
+ const col = columns.find((c) => c.id === filter.id);
+ const timeTag = localTags.find((tag) => tag.tag.includes(`**${filter.title}**`));
+ if (timeTag) {
+ const now = new Date();
+
+ const diff = now.getTime() - new Date(timeTag.value as string).getTime();
+ const ranges = col.elements as { value: string; label: string }[];
+ const dateRange = ranges.reduce((prev, curr) => {
+ if (parseInt(curr.value) < diff && curr.value > prev.value) {
+ return curr;
+ }
+ return prev;
+ });
+ if (dateRange) {
+ filter.tag = `**${filter.title}** is **${dateRange.label}**`;
+ filter = filter;
+ }
+ } else {
+ filter.tag = null;
+ }
+}
+
+export function setSizeFilter(localTags: TagValue[], filter: FilterData, columns: Column[]) {
+ const sizeTag = localTags.find((tag) => tag.tag.includes(`**${filter.title}**`));
+ const col = columns.find((c) => c.id === filter.id);
+ if (sizeTag) {
+ const size = sizeTag.value as string;
+ const ranges = col.elements as { value: string; label: string }[];
+ // find smallest range that is bigger than size
+ const sizeRange = ranges.reduce((prev, curr) => {
+ if (parseInt(size) >= parseInt(curr.value)) {
+ return curr;
+ }
+ return prev;
+ });
+ if (sizeRange) {
+ filter.tag = `**${filter.title}** is **${sizeRange.label}**`;
+ filter = filter;
+ }
+ } else {
+ filter.tag = null;
+ }
+}
+
+export function setStatusCodeFilter(localTags: TagValue[], filter: FilterData, columns: Column[]) {
+ const statusCodeTag = localTags.find((tag) => tag.tag.includes(`**${filter.title}**`));
+ const col = columns.find((c) => c.id === filter.id);
+
+ if (statusCodeTag) {
+ const ranges = col.elements as { value: number; label: string }[];
+
+ const codeRange = ranges.find((c) => c?.value && c.value === statusCodeTag.value);
+ if (codeRange) {
+ filter.tag = `**${filter.title}** is **${codeRange.label}**`;
+ filter = filter;
+ }
+ } else {
+ filter.tag = null;
+ }
+}
+
+export function setDateFilter(localTags: TagValue[], filter: FilterData, columns: Column[]) {
+ const dateTeag = localTags.find((tag) => tag.tag.includes(`**${filter.title}**`));
+ const col = columns.find((c) => c.id === filter.id);
+ if (dateTeag) {
+ const now = new Date();
+
+ const diff = now.getTime() - new Date(dateTeag.value as string).getTime();
+ const ranges = col.elements as { value: string; label: string }[];
+ const dateRange = ranges.reduce((prev, curr) => {
+ if (parseInt(curr.value) < diff && curr.value > prev.value) {
+ return curr;
+ }
+ return prev;
+ });
+ if (dateRange) {
+ filter.tag = `**${filter.title}** is **${dateRange.label}**`;
+ filter = filter;
+ }
+ } else {
+ filter.tag = null;
+ }
+}
diff --git a/src/lib/components/filters/store.ts b/src/lib/components/filters/store.ts
index 10cd6f183..bf8400910 100644
--- a/src/lib/components/filters/store.ts
+++ b/src/lib/components/filters/store.ts
@@ -1,5 +1,4 @@
import { goto } from '$app/navigation';
-
import { derived, get, writable } from 'svelte/store';
import { page } from '$app/stores';
import deepEqual from 'deep-equal';
diff --git a/src/lib/helpers/types.ts b/src/lib/helpers/types.ts
index f724ec101..ad99d94fe 100644
--- a/src/lib/helpers/types.ts
+++ b/src/lib/helpers/types.ts
@@ -39,6 +39,9 @@ export type Column = {
array?: boolean;
format?: string;
elements?: string[] | { value: string | number; label: string }[];
+ /**
+ * Set to true to hide this column by default
+ */
hide?: boolean;
};
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte
index b7f2ac859..025d61ed6 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte
@@ -9,12 +9,9 @@
import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system';
import { readOnly } from '$lib/stores/billing';
import Table from './table.svelte';
- import { Filters } from '$lib/components/filters';
- import { queries, tags } from '$lib/components/filters/store';
import { View } from '$lib/helpers/load';
import DeploymentCard from './(components)/deploymentCard.svelte';
import RedeployModal from './(modals)/redeployModal.svelte';
- import QuickFilters from './quickFilters.svelte';
import { canWriteFunctions } from '$lib/stores/roles';
import {
ActionMenu,
@@ -28,13 +25,13 @@
import { Click, trackEvent } from '$lib/actions/analytics';
import {
IconDotsHorizontal,
- IconFilterLine,
IconPlus,
IconRefresh,
IconTerminal
} from '@appwrite.io/pink-icons-svelte';
import { app } from '$lib/stores/app';
import CreateActionMenu from './(components)/createActionMenu.svelte';
+ import { QuickFilters } from '$lib/components/filters';
export let data;
@@ -42,11 +39,6 @@
let showAlert = true;
let selectedDeployment: Models.Deployment = null;
-
- function clearAll() {
- queries.clearAll();
- queries.apply();
- }
@@ -182,7 +174,7 @@
{#if data.deploymentList.total}
-
+
{/if}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte
index 09c7544cd..29c5532cb 100644
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte
+++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/+page.svelte
@@ -9,11 +9,11 @@
import { project } from '$routes/(console)/project-[project]/store';
import { base } from '$app/paths';
import { View } from '$lib/helpers/load';
- import QuickFilters from './quickFilters.svelte';
import { Icon, Layout } from '@appwrite.io/pink-svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import Table from './table.svelte';
import { columns } from './store';
+ import { QuickFilters } from '$lib/components/filters';
export let data;
@@ -30,7 +30,7 @@
-
+
{#if data?.executions?.total}
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/quickFilters.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/quickFilters.svelte
deleted file mode 100644
index f9bb43bf0..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/quickFilters.svelte
+++ /dev/null
@@ -1,233 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/quickFilters.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/quickFilters.svelte
deleted file mode 100644
index 9286f84d0..000000000
--- a/src/routes/(console)/project-[project]/functions/function-[function]/quickFilters.svelte
+++ /dev/null
@@ -1,231 +0,0 @@
-
-
-
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
index 35a10ebb7..22497ec3a 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
@@ -3,24 +3,22 @@
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { type Models } from '@appwrite.io/console';
- import { Filters } from '$lib/components/filters';
- import { queries, tags } from '$lib/components/filters/store';
import { View } from '$lib/helpers/load';
- import { ActionMenu, Icon, Layout, Popover, Tag } from '@appwrite.io/pink-svelte';
+ import { ActionMenu, Icon, Layout, Popover } from '@appwrite.io/pink-svelte';
import Table from './table.svelte';
- import QuickFilters from './quickFilters.svelte';
import RedeployModal from '../../redeployModal.svelte';
import CreateGitDeploymentModal from './createGitDeploymentModal.svelte';
import ConnectRepoModal from '../../(components)/connectRepoModal.svelte';
import { columns } from './store';
import CreateManualDeploymentModal from './createManualDeploymentModal.svelte';
import DeploymentMetrics from './deploymentMetrics.svelte';
- import { IconFilterLine, IconPlus } from '@appwrite.io/pink-icons-svelte';
+ import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import { onMount } from 'svelte';
import { sdk } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import CreateCliModal from './createCliModal.svelte';
+ import { QuickFilters } from '$lib/components/filters';
export let data;
@@ -33,11 +31,6 @@
let showConnectManual = false;
let showMobileFilters = false;
- function clearAll() {
- queries.clearAll();
- queries.apply();
- }
-
onMount(() => {
data?.query ? (showMobileFilters = true) : (showMobileFilters = false);
return sdk.forConsole.client.subscribe('console', (response) => {
@@ -53,106 +46,53 @@
-
-
- {#if data.deploymentList.total}
-
-
-
-
- {#if $tags?.length}
-
-
-
-
- {/if}
-
-
- {/if}
-
-
-
-
-
-
+
+ {#if data.deploymentList.total || data?.query}
+
+ {/if}
+
-
-
-
- More filters
-
-
-
-
-
-
-
-
- {#if data.deploymentList.total}
-
- {/if}
-
-
-
-
- {
- toggle(e);
- if (!hasInstallation) {
- showConnectRepo = true;
- } else {
- showCreateDeployment = true;
- }
- }}>
- Git
-
- {
- toggle(e);
- showConnectCLI = true;
- }}>
- CLI
-
- {
- toggle(e);
- showConnectManual = true;
- }}>
- Manual
-
-
-
-
-
-
+
+ {#if data.deploymentList.total}
+
+ {/if}
+
+
+
+
+ {
+ toggle(e);
+ if (!hasInstallation) {
+ showConnectRepo = true;
+ } else {
+ showCreateDeployment = true;
+ }
+ }}>
+ Git
+
+ {
+ toggle(e);
+ showConnectCLI = true;
+ }}>
+ CLI
+
+ {
+ toggle(e);
+ showConnectManual = true;
+ }}>
+ Manual
+
+
+
+
+
{#if data.deploymentList.total}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
deleted file mode 100644
index a6b357e3c..000000000
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
+++ /dev/null
@@ -1,276 +0,0 @@
-
-
-{#each [typeFilter] as filter}
-
-
-
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- option.checked = !option.checked;
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.checked ? option.value : null,
- filter?.array
- ? (filter.options
- .filter((opt) => opt.checked)
- .map((opt) => opt.value) ?? [])
- : []
- );
- }}>
- {option.label}
-
- {/each}
- {#if filter.options.some((option) => option.checked)}
- {
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- toggle(e);
- }}>
- Clear selection
-
- {/if}
-
-
-
-{/each}
-{#each [sizeFilter] as filter}
-
-
-
-
- {#key filter.tag}
-
- {filter?.tag ?? filter.title}
-
- {/key}
-
-
-
-
-
- {#each filter.options as option (option.value + option.checked)}
- {
- addFilterAndApply(
- filter.id,
- filter.title,
- filter.operator,
- filter?.array ? null : option.value,
- []
- );
- toggle(e);
- }}>
- {option.label}
-
- {/each}
- {#if filter?.tag}
- {
- filter.show = false;
- filter.tag = null;
- addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
- }}>
- Clear selection
-
- {/if}
-
-
-
-{/each}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
index 1fba88f94..166b666dd 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
@@ -13,8 +13,7 @@ export const columns = writable([
width: 110,
array: true,
format: 'enum',
- elements: ['ready', 'processing', 'building', 'waiting', 'cancelled', 'failed'],
- filter: false
+ elements: ['ready', 'processing', 'building', 'waiting', 'cancelled', 'failed']
},
{
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte
index d9d18f50c..88fde4c1c 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/settings/updateRuntimeSettings.svelte
@@ -4,6 +4,7 @@
import { CardGrid } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form, InputSelect } from '$lib/elements/forms';
+ import { capitalize } from '$lib/helpers/string';
import { iconPath } from '$lib/stores/app';
import { addNotification } from '$lib/stores/notifications';
import { getIconFromRuntime } from '$lib/stores/runtimes';
@@ -16,7 +17,7 @@
let buildRuntime = site?.buildRuntime;
let buildRuntimeOptions = framework.runtimes.map((runtime) => ({
- label: runtime,
+ label: capitalize(runtime),
value: runtime,
leadingHtml: `
`
}));