UNPKG

@spaceone/design-system

Version:
580 lines (499 loc) • 17.2 kB
import { Meta, Canvas, Story, ArgsTable } from '@storybook/addon-docs/blocks'; import PDynamicField from './PDynamicField.vue'; import { dynamicFieldTypes } from '@/data-display/dynamic/dynamic-field/type/field-schema'; <Meta title='Data Display/Dynamic/Dynamic Field' component={PDynamicField} argTypes={{ type: { name: 'type', type: {name: 'string'}, description: `The type of dynamic field. <br/> Available types: ${dynamicFieldTypes}`, defaultValue: `${dynamicFieldTypes[0]}`, table: { type: { summary: 'string' }, category: 'props', defaultValue: { summary: `'${dynamicFieldTypes[0]}'` }, }, control: { type: 'select', options: dynamicFieldTypes } }, options: { name: 'options', type: {name: 'object'}, description: `The options for field. Different by each type.`, defaultValue: {}, table: { type: { summary: 'object' }, category: 'props', defaultValue: { summary: `{}` }, }, control: { type: 'object', } }, data: { name: 'data', type: {name: 'any'}, description: `Data to display.`, defaultValue: 'data', table: { type: { summary: 'any' }, category: 'props', defaultValue: { summary: `undefined` }, }, control: { type: 'object', } }, extraData: { name: 'extraData', type: {name: 'any'}, description: `Extra data that is just passed to each field. <br/> It's useful when you want to reformat the data with handler.`, defaultValue: {}, table: { type: { summary: 'any' }, category: 'props', defaultValue: { summary: `{}` }, }, control: { type: 'object', } }, typeOptions: { name: 'typeOptions', type: {name: 'any'}, description: `Options that is the same with all fields even in recursive fields like enum type.`, defaultValue: {}, table: { type: { summary: 'any' }, category: 'props', defaultValue: { summary: `{}` }, }, control: { type: 'object', } }, handler: { name: 'handler', type: {name: 'function'}, description: `handler that reformat the data or options to display field.`, defaultValue: undefined, table: { type: { summary: 'function' }, category: 'props', defaultValue: { summary: `undefined` }, }, control: { type: 'object', } } }}/> export const Template = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { PDynamicField }, template: ` <div class="h-full w-full overflow p-8"> <p-dynamic-field v-bind="$props"></p-dynamic-field> </div> `, setup() { return {} } }); # Dynamic Field <br/> <br/> Dynamic fields provide several types to display data. <br/> <br/> ## Types The types that can be displayed as dynamic fields are as follows. - text - badge - datetime - dict - enum - size <br/> ## Options Additional options for displaying data by type can be set. Each type is slightly different, but there are also **common options**. ### Common Options - link - ex) https://google.com/ - sortable - Can be sorted by the field, default true - sort_key - Sorting key for each field (default sort key: key) - translation_id - Translation key for the label of the field(optional) - default - Used to display the default value when is undefined - is_optional - false (default) : Fields that are displayed by default even if the user does not select them - true : Fields that are not visible to the user by default, but can be changed through the Custom Table feature. - postfix - the value after value - ex) 70 + '%' - prefix - the value before value - ex) '$' + 3000 ```typescript interface CommonOptions { link?: string; sortable?: boolean; sort_key?: string; width?: string; translation_id?: string; default?: any; } ```` ## Type Options In the ```options``` props, data display metadata is injected for each field. <br/> On the other hand, properties that do not need to be added to options are injected into the ```typeOptions``` props because they do not change for each field.<br/> For example, ```timezone``` is not the property of the ```options``` props but of \`typeOptions\` props because ```timezone``` will be all the same to all fields. ```typescript interface DynamicFieldTypeOptions { timezone: string; } ``` <br/> ## Field Handler If you want to replace a value of field's ```props```, give ```handler```.<br/> This is useful when there are mutual influences depending on given props, such as when the ```type``` or ```options``` are changed by ```data```.<br/> ### When field handler works? **Handler works every time each props value are changed**.<br/> ### Parameter of field handler It takes **all dynamic field props object as a parameter** and returns **an object containing only changed dynamic field props**.<br/> Then, the returned object will be merged with the original props values.<br/> ### Usage of ExtraData props with field handler When you want to change field props values through a handler, and you need **additional data other than field props**, use ```extraData``` props.<br/> For example, let's say you have the following props.<br/> ```json5 { type: 'text', data: 'hello' } ``` If you want to attach 'world!', you can do it through a field handler as below.<br/> ```javascript const handler = ({data}) => { return { data: `${data} world!` } } ``` If you need data that is unknown at the time you inject the handler, props and handler function will be defined as below.<br/> ```json5 { type: 'text', data: 'hello', extraData: 'world!' } ``` ```javascript const handler = ({data, extraData}) => { return { data: `${data} ${extraData}` } } ``` If you give ```extraData``` props, **the handler will be executed when changes of ```extraData``` props are detected.** <br/> <br/> ### Field handler doesn't work recursively If the type is ```enum``` or the given data is iterable, field handler wouldn't be passed to the child.<br/> It will be invoked only at the parent level.<br/> For example, <br/> ```json5 [ { type: 'enum', data: 'first', options: { first: { type: 'badge', data: 'a' }, second: { type: 'badge', data: 'b' } }, handler: ... } ] ``` in this case, field handler will be invoked once with parent item.<br/> <br/> # Dynamic Field by Each Type <br/> ## Text Type The ```text``` type is the default type of the dynamic field.<br/> It's options are the same with the common options. <Canvas> <Story name="Text Type"> {{ components: { PDynamicField }, template: ` <div> <p-dynamic-field type="text" :options="{}" data="Basic text type"></p-dynamic-field> <br/><br/> <p-dynamic-field type="text" :options="{link: 'https://www.google.com'}" data="Text type with link"></p-dynamic-field> </div> `, }} </Story> </Canvas> <br/> ## Badge Type It's options are: ```typescript interface BadgeOptions extends CommonOptions { outline_color?: string; shape?: string; background_color?: string; text_color?: string; } ``` <Canvas> <Story name="Badge Type"> {{ components: { PDynamicField }, template: ` <div> <p-dynamic-field type="badge" :options="{}" data="Basic badge type"></p-dynamic-field> <br/><br/> <p-dynamic-field type="badge" :options="{outline_color: 'yellow.700', link: 'https://www.google.com'}" data="Outlined badge type with link"></p-dynamic-field> <br/><br/> <p-dynamic-field type="badge" :options="{shape: 'SQUARE'}" data="Square badge type"></p-dynamic-field> <br/><br/> <p-dynamic-field type="badge" :options="{text_color: 'peacock.700', background_color: 'coral.300'}" data="Custom Colored badge type"></p-dynamic-field> <br/><br/> </div> `, }} </Story> </Canvas> <br/> ## Datetime Type It's options are: ```typescript enum DATETIME_SOURCE_TYPE { iso8601 = 'iso8601', timestamp = 'timestamp' } interface DatetimeOptions extends CommonOptions { source_type: keyof typeof DATETIME_SOURCE_TYPE; source_format?: string; display_format?: string; } ``` <Canvas> <Story name="Datetime Type"> {{ components: { PDynamicField }, template: ` <div> <p class="font-bold text-lg">with iso8601 source type</p><br/> <span>basic: </span> <p-dynamic-field type="datetime" :options="{source_type: 'iso8601'}" :data="new Date().toISOString()"></p-dynamic-field> <br/><br/> <span>with different display format: </span> <p-dynamic-field type="datetime" :options="{source_type: 'iso8601', display_format: 'YY.MM.DD hh:mm:ss'}" :data="new Date().toISOString()"></p-dynamic-field> <br/><br/> <p class="font-bold text-lg">with timestamp source type</p><br/> <p-dynamic-field type="datetime" :options="{source_type: 'timestamp', source_format: 'seconds'}" :data="{seconds: '1616034252', nanos: 345000000}"></p-dynamic-field> <br/><br/> </div> `, }} </Story> </Canvas> <br/> ## Dict Type It's options are the same with the common options. <Canvas> <Story name="Dict Type"> {{ components: { PDynamicField }, template: ` <div> <p class="font-bold text-lg">basic</p><br/> <p-dynamic-field type="dict" :options="{}" :data="{a: 'aa', b: 'bb'}"></p-dynamic-field> <br/><br/> <p class="font-bold text-lg">with link</p><br/> <p-dynamic-field type="dict" :options="{link: 'https://www.google.com'}" :data="{a: 'aa', b: 'bb'}"></p-dynamic-field> <br/><br/> </div> `, }} </Story> </Canvas> <br/> ## State Type It's options are: ```typescript interface StateOptions extends CommonOptions { icon?: { image?: string; color?: string; }; text_color?: string; } ``` <Canvas> <Story name="State Type"> {{ components: { PDynamicField }, template: ` <div> <p class="font-bold text-lg">basic</p><br/> <p-dynamic-field type="state" :options="{}" data="RUNNING"></p-dynamic-field> <br/><br/> <p class="font-bold text-lg">with text color</p><br/> <p-dynamic-field type="state" :options="{text_color: 'green.400'}" data="RUNNING"></p-dynamic-field> <br/><br/> <p class="font-bold text-lg">with icon color</p><br/> <p-dynamic-field type="state" :options="{icon: {color: 'green.400'}}" data="RUNNING"></p-dynamic-field> <br/><br/> <p class="font-bold text-lg">with icon color</p><br/> <p-dynamic-field type="state" :options="{icon: {image: 'ic_stopping'}}" data="RUNNING"></p-dynamic-field> <br/><br/> </div> `, }} </Story> </Canvas> <br/> ## Enum Type It's options are: ```typescript interface EnumItem { name?: string; type: DynamicFieldType; options?: DynamicFieldOptions; default?: any; } interface EnumOptions { items?: EnumItem|string; default?: any; } ``` <Canvas> <Story name="Enum Type"> {{ components: { PDynamicField }, template: ` <div> <p class="font-bold text-lg">usual case</p><br/> <p-dynamic-field type="enum" :options="options" data="RUNNING"></p-dynamic-field><br/> <p-dynamic-field type="enum" :options="options" data="DEALLOCATED"></p-dynamic-field><br/> <p-dynamic-field type="enum" :options="options" data="PENDING"></p-dynamic-field><br/> <p-dynamic-field type="enum" :options="options" data="TERMINATED"></p-dynamic-field><br/> <br/> <p class="font-bold text-lg">default case</p><br/> <p-dynamic-field type="enum" :options="options"></p-dynamic-field><br/> <br/><br/> </div> `, setup() { const options = { items: { DEALLOCATED: { name: 'Deallocated', type: 'state', options: { text_color: 'red.500', icon: { color: 'red.500' } } }, PENDING: { name: 'Pending', type: 'state', options: { icon: { color: 'yellow.500' } } }, RUNNING: { name: 'Running', type: 'state', options: { icon: { color: 'green.500' } } }, TERMINATED: { name: 'Terminated', options: { text_color: 'gray.500', icon: { color: 'gray.500' }, description: 'This state is ' }, type: 'state', }, }, default: 'TERMINATED' } return { options } } }} </Story> </Canvas> <br/> ## Size Type It's options are: ```typescript interface SizeOptions extends CommonOptions { display_unit?: 'BYTES | KB | MB | GB | TB | PB'; source_unit?: 'BYTES | KB | MB | GB | TB | PB'; } ``` <Canvas> <Story name="Size Type"> {{ components: { PDynamicField }, template: ` <div> <p class="font-bold text-lg">auto case</p><br/> <p-dynamic-field type="size" :options="{}" :data="123456789"></p-dynamic-field><br/> <br/> <p class="font-bold text-lg">from bytes to bytes, mb, gb, tb, pb</p><br/> <p-dynamic-field type="size" :options="{display_unit: 'BYTES'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{display_unit: 'MB'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{display_unit: 'GB'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{display_unit: 'TB'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{display_unit: 'PB'}" :data="123456789"></p-dynamic-field><br/> <br/> <p class="font-bold text-lg">from bytes, mb, gb, tb, pb to auto</p><br/> <p-dynamic-field type="size" :options="{source_unit: 'BYTES'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{source_unit: 'MB'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{source_unit: 'GB'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{source_unit: 'TB'}" :data="123456789"></p-dynamic-field><br/> <p-dynamic-field type="size" :options="{source_unit: 'PB'}" :data="123456789"></p-dynamic-field><br/> <br/> <p class="font-bold text-lg">from kb to gb</p><br/> <p-dynamic-field type="size" :options="{source_unit: 'KB', display_unit: 'GB'}" :data="123456789"></p-dynamic-field><br/> <br/> </div> `, }} </Story> </Canvas> <br/> # Playground <Canvas> <Story name="Playground"> {Template.bind({})} </Story> </Canvas> <ArgsTable story="Playground"/>