Skip to content

Commit

Permalink
Merge pull request #11637 from storybookjs/11571-fix-prefix-redirect
Browse files Browse the repository at this point in the history
Core: Fix prefix redirect
  • Loading branch information
shilman authored Jul 22, 2020
2 parents 2585ac9 + 2dff01f commit 28e65b0
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 2 deletions.
11 changes: 11 additions & 0 deletions examples/official-storybook/stories/core/prefix.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Very simple stories to show what happens when one story's id is a prefix of anothers'
// Repro for https://github.com/storybookjs/storybook/issues/11571

export default {
title: 'Core/Prefix',
};

const Template = () => 'Story';

export const prefixAndName = Template.bind({});
export const prefix = Template.bind({});
11 changes: 11 additions & 0 deletions lib/client-api/src/story_store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,17 @@ describe('preview.story_store', () => {

expect(store.getSelection()).toEqual(undefined);
});

// See #11571
it('does NOT select an earlier story that this story id is a prefix of', () => {
const store = new StoryStore({ channel });
store.setSelectionSpecifier({ storySpecifier: 'a--3', viewMode: 'story' });
addStoryToStore(store, 'a', '31', () => 0);
addStoryToStore(store, 'a', '3', () => 0);
store.finishConfiguring();

expect(store.getSelection()).toEqual({ storyId: 'a--3', viewMode: 'story' });
});
});

describe('if you use no specifier', () => {
Expand Down
4 changes: 3 additions & 1 deletion lib/client-api/src/story_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ export default class StoryStore {
// '*' means select the first story. If there is none, we have no selection.
[foundStory] = stories;
} else if (typeof storySpecifier === 'string') {
foundStory = Object.values(stories).find((s) => s.id.startsWith(storySpecifier));
// Find the story with the shortest id that matches the specifier (see #11571)
const foundStories = Object.values(stories).filter((s) => s.id.startsWith(storySpecifier));
[foundStory] = foundStories.sort((a, b) => a.id.length - b.id.length);
} else {
// Try and find a story matching the name/kind, setting no selection if they don't exist.
const { name, kind } = storySpecifier;
Expand Down
11 changes: 10 additions & 1 deletion lib/ui/src/components/preview/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment, FunctionComponent, useMemo, useEffect } from 'react';
import React, { Fragment, FunctionComponent, useMemo, useEffect, useRef } from 'react';
import { Helmet } from 'react-helmet-async';

import merge from '@storybook/api/dist/lib/merge';
Expand Down Expand Up @@ -150,7 +150,16 @@ const Preview: FunctionComponent<PreviewProps> = (props) => {
const isToolshown =
!(viewMode === 'docs' && tabs.filter((t) => !t.hidden).length < 2) && options.isToolshown;

const initialRender = useRef(true);
useEffect(() => {
// Don't emit the event on first ("real") render, only when story or mode changes
if (initialRender.current) {
// We initially render without a story set, which isn't all that interesting, let's ignore
if (story) {
initialRender.current = false;
}
return;
}
if (story && viewMode && viewMode.match(/docs|story/)) {
const { refId, id } = story;
api.emit(SET_CURRENT_STORY, {
Expand Down

0 comments on commit 28e65b0

Please sign in to comment.