fix(editor): Remove resource center tooltip (no-changelog) (#30468)

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Romeo Balta 2026-05-14 16:28:02 +01:00 committed by GitHub
parent 71dab38e82
commit 94113f44a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 0 additions and 301 deletions

View File

@ -1213,7 +1213,6 @@
"experiments.resourceCenter.sidebar": "Resources",
"experiments.resourceCenter.template.setupTime": "{minutes} minute set up",
"experiments.resourceCenter.title": "Resources",
"experiments.resourceCenter.tooltip.text": "Get inspired and learn with use cases",
"experiments.resourceCenter.video.level": "Level: {level}",
"experiments.templatesDataQuality.modalTitle": "Featured templates",
"error": "Error",

View File

@ -24,7 +24,6 @@ import MainSidebarHeader from '@/app/components/MainSidebarHeader.vue';
import BottomMenu from '@/app/components/BottomMenu.vue';
import MainSidebarSourceControl from '@/app/components/MainSidebarSourceControl.vue';
import ProjectNavigation from '@/features/collaboration/projects/components/ProjectNavigation.vue';
import ResourceCenterTooltip from '@/experiments/resourceCenter/components/ResourceCenterTooltip.vue';
import { useResourceCenterStore } from '@/experiments/resourceCenter/stores/resourceCenter.store';
import { LOCAL_STORAGE_SIDEBAR_WIDTH } from '@/app/constants';
import { useSidebarExpandedExperiment } from '@/experiments/sidebarExpanded';
@ -285,10 +284,6 @@ function openCommandBar(event: MouseEvent) {
const handleSelect = (key: string) => {
switch (key) {
case 'resource-center': {
resourceCenterStore.markResourceCenterTooltipDismissed();
break;
}
case 'about': {
trackHelpItemClick('about');
uiStore.openModal(ABOUT_MODAL_KEY);
@ -384,7 +379,6 @@ useKeybindings({
@select="handleSelect"
/>
<MainSidebarSourceControl :is-collapsed="isCollapsed" />
<ResourceCenterTooltip />
</N8nResizeWrapper>
</template>

View File

@ -1,203 +0,0 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { useI18n } from '@n8n/i18n';
import { N8nIcon, N8nTooltip } from '@n8n/design-system';
import { useResourceCenterStore } from '../stores/resourceCenter.store';
import { useSidebarLayout } from '@/app/composables/useSidebarLayout';
const resourceCenterStore = useResourceCenterStore();
const { isCollapsed } = useSidebarLayout();
const {
markResourceCenterTooltipDismissed,
trackResourceCenterTooltipView,
trackResourceCenterTooltipDismiss,
} = resourceCenterStore;
const locale = useI18n();
const tooltipRef = ref<HTMLElement>();
const isVisible = ref(false);
const position = ref({ top: 0, left: 0 });
const tooltipKey = ref(0);
const shouldShow = computed(() => resourceCenterStore.shouldShowResourceCenterTooltip);
const tooltipText = computed(() => {
return locale.baseText('experiments.resourceCenter.tooltip.text');
});
const calculatePosition = () => {
const resourceCenterElement = document.querySelector(
'[data-test-id="menu-item"][id="resource-center"]',
);
if (!resourceCenterElement) return;
const menuRect = resourceCenterElement.getBoundingClientRect();
position.value = {
top: menuRect.top + menuRect.height / 2 - 5,
left: menuRect.right,
};
tooltipKey.value++;
};
const showTooltip = async () => {
isVisible.value = true;
trackResourceCenterTooltipView();
await nextTick();
calculatePosition();
};
const hideTooltip = () => {
isVisible.value = false;
};
const handleDismiss = () => {
trackResourceCenterTooltipDismiss();
markResourceCenterTooltipDismissed();
hideTooltip();
};
const handleResize = () => {
if (isVisible.value) {
calculatePosition();
}
};
const handleContentResize = () => {
if (isVisible.value) {
setTimeout(() => {
calculatePosition();
}, 500);
}
};
watch(
shouldShow,
async (newValue) => {
if (newValue) {
await showTooltip();
} else {
hideTooltip();
}
},
{ immediate: true },
);
// Recalculate position when sidebar collapse state changes
watch(isCollapsed, async () => {
if (isVisible.value) {
await nextTick();
// Small delay to allow sidebar animation to complete
setTimeout(() => {
calculatePosition();
}, 300);
}
});
let contentResizeObserver: ResizeObserver | null = null;
onMounted(() => {
window.addEventListener('resize', handleResize);
window.addEventListener('scroll', handleResize);
const contentElement = document.getElementById('content');
if (contentElement) {
contentResizeObserver = new ResizeObserver(handleContentResize);
contentResizeObserver.observe(contentElement);
}
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
window.removeEventListener('scroll', handleResize);
if (contentResizeObserver) {
contentResizeObserver.disconnect();
contentResizeObserver = null;
}
});
</script>
<template>
<Teleport to="body">
<div
v-if="isVisible && shouldShow"
ref="tooltipRef"
:key="tooltipKey"
:class="$style.triggerContainer"
:style="{
position: 'fixed',
top: position.top + 'px',
left: position.left + 'px',
}"
>
<N8nTooltip
:visible="true"
placement="right"
:show-arrow="true"
:popper-style="{ maxWidth: '260px', minWidth: '240px' }"
>
<template #content>
<div :class="$style.tooltipContent">
<span :class="$style.text">
{{ tooltipText }}
</span>
<button
:class="$style.dismissButton"
type="button"
aria-label="Dismiss tooltip"
@click="handleDismiss"
>
<N8nIcon icon="x" size="small" />
</button>
</div>
</template>
<div :class="$style.tooltipTrigger"></div>
</N8nTooltip>
</div>
</Teleport>
</template>
<style lang="scss" module>
.triggerContainer {
z-index: 9999;
pointer-events: auto;
}
.tooltipTrigger {
width: 1px;
height: 1px;
opacity: 0;
}
.tooltipContent {
display: flex;
align-items: flex-start;
gap: var(--spacing--2xs);
}
.text {
flex: 1;
font-size: var(--font-size--2xs);
line-height: var(--line-height--md);
}
.dismissButton {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--color--text--tint-1);
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
flex-shrink: 0;
&:hover {
color: var(--color--text);
}
}
</style>

View File

@ -1,58 +0,0 @@
import { createComponentRenderer } from '@/__tests__/render';
import { screen, waitFor } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import ResourceCenterTooltip from '../ResourceCenterTooltip.vue';
const mocks = vi.hoisted(() => ({
trackView: vi.fn(),
trackDismiss: vi.fn(),
markDismissed: vi.fn(),
}));
vi.mock('../../stores/resourceCenter.store', () => ({
useResourceCenterStore: () => ({
shouldShowResourceCenterTooltip: true,
trackResourceCenterTooltipView: mocks.trackView,
trackResourceCenterTooltipDismiss: mocks.trackDismiss,
markResourceCenterTooltipDismissed: mocks.markDismissed,
}),
}));
vi.mock('@/app/composables/useSidebarLayout', () => ({
useSidebarLayout: () => ({
isCollapsed: false,
}),
}));
const renderComponent = createComponentRenderer(ResourceCenterTooltip, {
global: {
stubs: {
N8nTooltip: {
template: '<div><slot name="content" /><slot /></div>',
},
N8nIcon: true,
},
},
});
describe('ResourceCenterTooltip', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('tracks a tooltip view when it becomes visible', async () => {
renderComponent();
await waitFor(() => expect(mocks.trackView).toHaveBeenCalledTimes(1));
expect(screen.getByText('Get inspired and learn with use cases')).toBeInTheDocument();
});
it('tracks dismissal and persists the dismissed state', async () => {
renderComponent();
await userEvent.click(await screen.findByRole('button', { name: 'Dismiss tooltip' }));
expect(mocks.trackDismiss).toHaveBeenCalledTimes(1);
expect(mocks.markDismissed).toHaveBeenCalledTimes(1);
});
});

View File

@ -75,16 +75,6 @@ describe('resourceCenter.store', () => {
);
});
describe('tooltip persistence (GRO-284 fix)', () => {
it('reads dismissed state from localStorage on init', () => {
localStorage.setItem('n8n-resourceCenter-tooltipDismissed', 'true');
setActivePinia(createPinia());
const store = useResourceCenterStore();
// shouldShowResourceCenterTooltip should be false since tooltip was dismissed
expect(store.shouldShowResourceCenterTooltip).toBe(false);
});
});
describe('sidebar auto-expand', () => {
it('stops auto-expanding after the sidebar is marked as expanded', () => {
mocks.getVariant.mockReturnValue('variant');

View File

@ -14,7 +14,6 @@ import { OPEN_AI_API_CREDENTIAL_TYPE, deepCopy } from 'n8n-workflow';
import { quickStartWorkflows } from '../data/quickStartWorkflows';
const LOCAL_STORAGE_CREDENTIAL_KEY = 'N8N_READY_TO_RUN_OPENAI_CREDENTIAL_ID';
const TOOLTIP_STORAGE_KEY = 'n8n-resourceCenter-tooltipDismissed';
const SIDEBAR_AUTO_EXPANDED_KEY = 'n8n-resourceCenter-sidebarAutoExpanded';
export const useResourceCenterStore = defineStore('resourceCenter', () => {
@ -26,7 +25,6 @@ export const useResourceCenterStore = defineStore('resourceCenter', () => {
const router = useRouter();
const isLoadingTemplates = ref(false);
const hasTooltipBeenDismissed = ref(localStorage.getItem(TOOLTIP_STORAGE_KEY) === 'true');
const hasSidebarBeenAutoExpanded = ref(
localStorage.getItem(SIDEBAR_AUTO_EXPANDED_KEY) === 'true',
);
@ -37,23 +35,6 @@ export const useResourceCenterStore = defineStore('resourceCenter', () => {
RESOURCE_CENTER_EXPERIMENT.variant,
);
const shouldShowResourceCenterTooltip = computed(() => {
return isFeatureEnabled() && !hasTooltipBeenDismissed.value;
});
function markResourceCenterTooltipDismissed() {
hasTooltipBeenDismissed.value = true;
localStorage.setItem(TOOLTIP_STORAGE_KEY, 'true');
}
function trackResourceCenterTooltipView() {
telemetry.track('User viewed resource center tooltip');
}
function trackResourceCenterTooltipDismiss() {
telemetry.track('User dismissed resource center tooltip');
}
async function fetchTemplateById(templateId: number): Promise<ITemplatesWorkflowFull | null> {
try {
return await templatesStore.fetchTemplateById(templateId.toString());
@ -142,17 +123,13 @@ export const useResourceCenterStore = defineStore('resourceCenter', () => {
return {
isFeatureEnabled,
isLoadingTemplates,
shouldShowResourceCenterTooltip,
shouldAutoExpandSidebar,
fetchTemplateById,
loadTemplates,
getTemplateRoute,
createAndOpenQuickStartWorkflow,
markResourceCenterTooltipDismissed,
markSidebarAutoExpanded,
trackResourceCenterView,
trackResourceCenterTooltipView,
trackResourceCenterTooltipDismiss,
trackTileClick,
};
});