Skip to content

Commit

Permalink
Fix active tab not updating on prop change (#2712)
Browse files Browse the repository at this point in the history
  • Loading branch information
anbraten authored Nov 3, 2023
1 parent fd8f35a commit fe48928
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 43 deletions.
5 changes: 4 additions & 1 deletion web/src/components/layout/scaffold/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ const props = defineProps<{
search?: string;
fullWidth?: boolean;
}>();
defineEmits(['update:search']);
defineEmits<{
(event: 'update:search', query: string): void;
}>();
const searchBoxPresent = props.search !== undefined;
</script>
26 changes: 20 additions & 6 deletions web/src/components/layout/scaffold/Scaffold.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</template>

<script setup lang="ts">
import { toRef } from 'vue';
import { computed, ref, watch } from 'vue';
import Container from '~/components/layout/Container.vue';
import { useTabsProvider } from '~/compositions/useTabs';
Expand All @@ -33,23 +33,37 @@ const props = defineProps<{
// Tabs
enableTabs?: boolean;
disableHashMode?: boolean;
disableTabUrlHashMode?: boolean;
activeTab?: string;
// Content
fluidContent?: boolean;
}>();
const emit = defineEmits<{
(event: 'update:activeTab', value: string): void;
(event: 'update:activeTab', value: string | undefined): void;
(event: 'update:search', value: string): void;
}>();
if (props.enableTabs) {
const internalActiveTab = ref(props.activeTab);
watch(
() => props.activeTab,
(activeTab) => {
internalActiveTab.value = activeTab;
},
);
useTabsProvider({
activeTabProp: toRef(props, 'activeTab'),
disableHashMode: toRef(props, 'disableHashMode'),
updateActiveTabProp: (value) => emit('update:activeTab', value),
activeTab: computed({
get: () => internalActiveTab.value,
set: (value) => {
internalActiveTab.value = value;
emit('update:activeTab', value);
},
}),
disableUrlHashMode: computed(() => props.disableTabUrlHashMode || false),
});
}
</script>
5 changes: 3 additions & 2 deletions web/src/components/layout/scaffold/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ import { Tab, useTabsClient } from '~/compositions/useTabs';
const router = useRouter();
const route = useRoute();
const { activeTab, tabs, disableHashMode } = useTabsClient();
const { activeTab, tabs, disableUrlHashMode } = useTabsClient();
async function selectTab(tab: Tab) {
if (tab.id === undefined) {
return;
}
activeTab.value = tab.id;
if (!disableHashMode.value) {
if (!disableUrlHashMode.value) {
await router.replace({ params: route.params, hash: `#${tab.id}` });
}
}
Expand Down
45 changes: 13 additions & 32 deletions web/src/compositions/useTabs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, inject, onMounted, provide, Ref, ref } from 'vue';
import { inject, onMounted, provide, Ref, ref } from 'vue';
import { useRoute } from 'vue-router';

export type Tab = {
Expand All @@ -7,58 +7,39 @@ export type Tab = {
};

export function useTabsProvider({
activeTabProp,
disableHashMode,
updateActiveTabProp,
activeTab,
disableUrlHashMode,
}: {
activeTabProp: Ref<string | undefined>;
updateActiveTabProp: (tab: string) => void;
disableHashMode: Ref<boolean>;
activeTab: Ref<string | undefined>;
disableUrlHashMode: Ref<boolean>;
}) {
const route = useRoute();

const tabs = ref<Tab[]>([]);
const activeTab = ref<string>('');

provide('tabs', tabs);
provide(
'disable-hash-mode',
computed(() => disableHashMode.value),
);
provide(
'active-tab',
computed({
get: () => activeTab.value,
set: (value) => {
activeTab.value = value;
updateActiveTabProp(value);
},
}),
);
provide('disable-url-hash-mode', disableUrlHashMode);
provide('active-tab', activeTab);

onMounted(() => {
if (activeTabProp.value) {
activeTab.value = activeTabProp.value;
if (activeTab.value !== undefined) {
return;
}

const hashTab = route.hash.replace(/^#/, '');
if (hashTab) {
activeTab.value = hashTab;
return;
}
activeTab.value = tabs.value[0].id;
// eslint-disable-next-line no-param-reassign
activeTab.value = hashTab ?? tabs.value[0].id;
});
}

export function useTabsClient() {
const tabs = inject<Ref<Tab[]>>('tabs');
const disableHashMode = inject<Ref<boolean>>('disable-hash-mode');
const disableUrlHashMode = inject<Ref<boolean>>('disable-url-hash-mode');
const activeTab = inject<Ref<string>>('active-tab');

if (activeTab === undefined || tabs === undefined || disableHashMode === undefined) {
if (activeTab === undefined || tabs === undefined || disableUrlHashMode === undefined) {
throw new Error('Please use this "useTabsClient" composition inside a component running "useTabsProvider".');
}

return { activeTab, tabs, disableHashMode };
return { activeTab, tabs, disableUrlHashMode };
}
2 changes: 1 addition & 1 deletion web/src/views/repo/RepoWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
v-if="repo && repoPermissions && $route.meta.repoHeader"
v-model:activeTab="activeTab"
enable-tabs
disable-hash-mode
disable-tab-url-hash-mode
>
<template #title>
<span class="flex">
Expand Down
2 changes: 1 addition & 1 deletion web/src/views/repo/pipeline/PipelineWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
v-if="pipeline && repo"
v-model:activeTab="activeTab"
enable-tabs
disable-hash-mode
disable-tab-url-hash-mode
:go-back="goBack"
:fluid-content="activeTab === 'tasks'"
full-width-header
Expand Down

0 comments on commit fe48928

Please sign in to comment.