├── .circleci └── config.yml ├── .editorconfig ├── .flake8 ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── testing.yml │ └── update-html.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .nvmrc ├── .pylintrc ├── @plotly ├── dash-component-plugins │ ├── LICENSE │ ├── babel.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── History.js │ │ ├── dynamicImport.js │ │ └── index.js │ └── webpack.config.js ├── dash-generator-test-component-nested │ ├── MANIFEST.in │ ├── README.md │ ├── babel.config.js │ ├── base │ │ └── __init__.py │ ├── package-lock.json │ ├── package.json │ ├── setup.py │ ├── src │ │ ├── components │ │ │ └── MyNestedComponent.js │ │ └── index.js │ └── webpack.config.js ├── dash-generator-test-component-standard │ ├── MANIFEST.in │ ├── README.md │ ├── babel.config.js │ ├── base │ │ ├── __init__.py │ │ ├── godfather.ttf │ │ └── style.css │ ├── package-lock.json │ ├── package.json │ ├── setup.py │ ├── src │ │ ├── components │ │ │ └── MyStandardComponent.js │ │ └── index.js │ └── webpack.config.js ├── dash-generator-test-component-typescript │ ├── README.md │ ├── _dash_prop_typing.py │ ├── babel.config.js │ ├── base │ │ ├── __init__.py │ │ └── py.typed │ ├── generator.test.ts │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── setup.py │ ├── src │ │ ├── components │ │ │ ├── EmptyComponent.tsx │ │ │ ├── FCComponent.tsx │ │ │ ├── MemoTypeScriptComponent.tsx │ │ │ ├── MixedComponent.tsx │ │ │ ├── RequiredChildrenComponent.tsx │ │ │ ├── StandardComponent.react.js │ │ │ ├── TypeScriptClassComponent.tsx │ │ │ ├── TypeScriptComponent.tsx │ │ │ └── WrappedHTML.tsx │ │ ├── index.ts │ │ └── props.ts │ ├── tsconfig.json │ └── webpack.config.js ├── dash-jupyterlab │ ├── .prettierrc │ ├── lib │ │ ├── index.d.ts │ │ └── index.js │ ├── package.json │ ├── src │ │ └── index.ts │ ├── style │ │ └── index.css │ ├── tsconfig.json │ └── yarn.lock ├── dash-test-components │ ├── MANIFEST.in │ ├── README.md │ ├── babel.config.js │ ├── base │ │ └── __init__.py │ ├── package-lock.json │ ├── package.json │ ├── setup.py │ ├── src │ │ ├── components │ │ │ ├── AddPropsComponent.js │ │ │ ├── ArrayOfExactOrShapeWithNodePropAssignNone.js │ │ │ ├── AsyncComponent.js │ │ │ ├── CollapseComponent.js │ │ │ ├── ComponentAsProp.js │ │ │ ├── DelayedEventComponent.js │ │ │ ├── DrawCounter.js │ │ │ ├── ExternalComponent.js │ │ │ ├── FragmentComponent.js │ │ │ ├── MyPersistedComponent.js │ │ │ ├── MyPersistedComponentNested.js │ │ │ ├── ReceivePropsComponent.js │ │ │ ├── RenderType.js │ │ │ ├── ShapeOrExactKeepOrderComponent.js │ │ │ ├── StyledComponent.js │ │ │ └── WidthComponent.js │ │ ├── fragments │ │ │ ├── AsyncComponent.js │ │ │ └── AsyncComponentLoader.js │ │ └── index.js │ └── webpack.config.js ├── eslint-config-dash │ ├── .gitignore │ ├── README.md │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── typescript.js ├── prettier-config-dash │ ├── .gitignore │ ├── README.md │ ├── index.js │ ├── package-lock.json │ └── package.json └── webpack-dash-dynamic-import │ ├── LICENSE │ ├── package.json │ └── src │ └── index.js ├── CHANGELOG.md ├── CITATION.cff ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MAKE_A_NEW_BACK_END.md ├── MANIFEST.in ├── README.md ├── components ├── dash-core-components │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc │ ├── .flake8 │ ├── .gitignore │ ├── .lib.babelrc │ ├── .prettierrc │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── MANIFEST.in │ ├── README.md │ ├── __init__.py │ ├── babel.config.js │ ├── dash-info.yaml │ ├── dash_core_components_base │ │ ├── __init__.py │ │ └── express.py │ ├── dash_prop_typing.py │ ├── images │ │ └── upload-component.gif │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── packages │ │ └── README.md │ ├── pytest.ini │ ├── renovate.json │ ├── setup.py │ ├── src │ │ ├── components │ │ │ ├── Checklist.react.js │ │ │ ├── Clipboard.react.js │ │ │ ├── ConfirmDialog.react.js │ │ │ ├── ConfirmDialogProvider.react.js │ │ │ ├── DatePickerRange.react.js │ │ │ ├── DatePickerSingle.react.js │ │ │ ├── Download.react.js │ │ │ ├── Dropdown.react.js │ │ │ ├── Geolocation.react.js │ │ │ ├── Graph.react.js │ │ │ ├── Input.react.js │ │ │ ├── Interval.react.js │ │ │ ├── Link.react.js │ │ │ ├── Loading.react.js │ │ │ ├── Location.react.js │ │ │ ├── Markdown.react.js │ │ │ ├── RadioItems.react.js │ │ │ ├── RangeSlider.react.js │ │ │ ├── Slider.react.js │ │ │ ├── Store.react.js │ │ │ ├── Tab.react.js │ │ │ ├── Tabs.react.js │ │ │ ├── Textarea.react.js │ │ │ ├── Tooltip.react.js │ │ │ ├── Upload.react.js │ │ │ └── css │ │ │ │ ├── Dropdown.css │ │ │ │ ├── input.css │ │ │ │ ├── react-dates@20.1.0-fix.css │ │ │ │ ├── react-select@1.0.0-rc.3.min.css │ │ │ │ ├── react-virtualized@9.9.0.css │ │ │ │ └── sliders.css │ │ ├── fragments │ │ │ ├── DatePickerRange.react.js │ │ │ ├── DatePickerSingle.react.js │ │ │ ├── Dropdown.react.js │ │ │ ├── Graph.privateprops.js │ │ │ ├── Graph.react.js │ │ │ ├── Loading │ │ │ │ └── spinners │ │ │ │ │ ├── CircleSpinner.jsx │ │ │ │ │ ├── CubeSpinner.jsx │ │ │ │ │ ├── DebugTitle.jsx │ │ │ │ │ ├── DefaultSpinner.jsx │ │ │ │ │ ├── DotSpinner.jsx │ │ │ │ │ └── GraphSpinner.jsx │ │ │ ├── Markdown.react.js │ │ │ ├── Math.react.js │ │ │ ├── RangeSlider.react.js │ │ │ ├── Slider.react.js │ │ │ └── Upload.react.js │ │ ├── index.js │ │ ├── third-party │ │ │ └── highlight.js │ │ └── utils │ │ │ ├── DatePickerPersistence.js │ │ │ ├── LazyLoader │ │ │ ├── datePickerRange.js │ │ │ ├── datePickerSingle.js │ │ │ ├── dropdown.js │ │ │ ├── graph.js │ │ │ ├── hljs.js │ │ │ ├── markdown.js │ │ │ ├── mathjax.js │ │ │ ├── plotly.js │ │ │ ├── rangeSlider.js │ │ │ ├── slider.js │ │ │ └── upload.js │ │ │ ├── LoadingElement.js │ │ │ ├── MarkdownHighlighter.js │ │ │ ├── ResizeDetector.js │ │ │ ├── computeSliderMarkers.js │ │ │ ├── computeSliderStyle.js │ │ │ ├── convertToMoment.js │ │ │ ├── formatSliderTooltip.js │ │ │ ├── mathjax.js │ │ │ └── optionTypes.js │ ├── tests │ │ ├── assets │ │ │ ├── image.png │ │ │ ├── input.css │ │ │ └── tab.css │ │ ├── conftest.py │ │ ├── dash_core_components_page.py │ │ └── integration │ │ │ ├── calendar │ │ │ ├── test_calendar_props.py │ │ │ ├── test_date_picker_persistence.py │ │ │ ├── test_date_picker_range.py │ │ │ └── test_date_picker_single.py │ │ │ ├── clipboard │ │ │ └── test_clipboard.py │ │ │ ├── confirmdialog │ │ │ └── test_confirm.py │ │ │ ├── download │ │ │ ├── download-assets │ │ │ │ └── chuck.jpg │ │ │ ├── test_download.py │ │ │ ├── test_download_dataframe.py │ │ │ └── test_download_file.py │ │ │ ├── dropdown │ │ │ ├── test_clearable_false.py │ │ │ ├── test_dropdown_radioitems_checklist_shorthands.py │ │ │ ├── test_dynamic_options.py │ │ │ ├── test_remove_option.py │ │ │ ├── test_search_value.py │ │ │ ├── test_styles.py │ │ │ └── test_visibility.py │ │ │ ├── geolocation │ │ │ └── test_geolocation.py │ │ │ ├── graph │ │ │ ├── test_graph_basics.py │ │ │ ├── test_graph_purge.py │ │ │ ├── test_graph_responsive.py │ │ │ └── test_graph_varia.py │ │ │ ├── input │ │ │ ├── conftest.py │ │ │ ├── test_debounce.py │ │ │ ├── test_input_and_state.py │ │ │ ├── test_input_basics.py │ │ │ └── test_number_input.py │ │ │ ├── interval │ │ │ └── test_interval.py │ │ │ ├── link │ │ │ ├── test_absolute_path.py │ │ │ ├── test_link_children.py │ │ │ ├── test_link_event.py │ │ │ └── test_title_prop.py │ │ │ ├── loading │ │ │ └── test_loading_component.py │ │ │ ├── location │ │ │ └── test_location_callback.py │ │ │ ├── markdown │ │ │ └── test_markdown.py │ │ │ ├── misc │ │ │ ├── conftest.py │ │ │ ├── test_bcdp_auto_id.py │ │ │ ├── test_dcc_components_as_props.py │ │ │ ├── test_inline.py │ │ │ ├── test_markdown_highlight.py │ │ │ ├── test_persistence.py │ │ │ └── test_platter.py │ │ │ ├── sliders │ │ │ ├── assets │ │ │ │ └── transform.js │ │ │ ├── test_sliders.py │ │ │ └── test_sliders_shorthands.py │ │ │ ├── store │ │ │ ├── conftest.py │ │ │ ├── test_component_props.py │ │ │ ├── test_data_lifecycle.py │ │ │ └── test_store_data.py │ │ │ ├── tab │ │ │ ├── test_tabs.py │ │ │ └── test_tabs_with_graphs.py │ │ │ ├── test_title_props.py │ │ │ ├── tooltip │ │ │ └── test_tooltip.py │ │ │ └── upload │ │ │ ├── test_children_accept_any_component.py │ │ │ ├── test_upload_different_file_types.py │ │ │ └── upload-assets │ │ │ ├── upft001.csv │ │ │ ├── upft001.png │ │ │ ├── upft001.svg │ │ │ ├── upft001.xls │ │ │ └── upft001.xlsx │ ├── vignettes │ │ ├── dash-core-components.Rmd │ │ ├── dash-core-components.html │ │ └── dash-core-components.html.asis │ └── webpack.config.js ├── dash-html-components │ ├── .builderrc │ ├── .eslintignore │ ├── .eslintrc │ ├── .gitignore │ ├── .pylintrc │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── LICENSE.md │ ├── MANIFEST.in │ ├── README.md │ ├── babel.config.js │ ├── dash-info.yaml │ ├── dash_html_components_base │ │ └── __init__.py │ ├── package-lock.json │ ├── package.json │ ├── scripts │ │ ├── .eslintrc.json │ │ ├── data │ │ │ ├── attributes.json │ │ │ └── elements.txt │ │ ├── extract-all.sh │ │ ├── extract-attributes.js │ │ ├── extract-elements.js │ │ ├── generate-all.sh │ │ ├── generate-components.js │ │ └── generate-index.js │ ├── setup.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_dash_html_components.py │ │ ├── test_div_tabIndex.py │ │ ├── test_integration.py │ │ └── utils.py │ ├── vignettes │ │ ├── dash-html-components.Rmd │ │ ├── dash-html-components.html │ │ └── dash-html-components.html.asis │ └── webpack.config.js └── dash-table │ ├── .config │ └── webpack │ │ ├── base.js │ │ └── base.preprocessing.js │ ├── .eslintrc.js │ ├── .flake8 │ ├── .gitignore │ ├── .npmignore │ ├── .prettierrc │ ├── .pylintrc │ ├── .storybook │ ├── babel.config.js │ └── main.js │ ├── .test_durations │ ├── @Types │ └── modules.d.ts │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE │ ├── MANIFEST.in │ ├── README.md │ ├── __init__.py │ ├── app.json │ ├── babel.config.js │ ├── cspell.json │ ├── dash-info.yaml │ ├── dash_table_base │ ├── Format.py │ ├── FormatTemplate.py │ └── __init__.py │ ├── demo │ ├── App.tsx │ ├── AppMode.ts │ ├── data.ts │ ├── index.html │ ├── index.js │ └── style.less │ ├── generator │ └── cssPropertiesGenerator.js │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── pytest.ini │ ├── renovate.json │ ├── setup.py │ ├── src │ ├── core │ │ ├── Clipboard.ts │ │ ├── Logger │ │ │ ├── DebugLevel.ts │ │ │ ├── LogLevel.ts │ │ │ └── index.ts │ │ ├── Stylesheet.ts │ │ ├── browser │ │ │ ├── DOM.ts │ │ │ ├── isChrome.ts │ │ │ └── scrollbarWidth.ts │ │ ├── cache │ │ │ ├── index.ts │ │ │ ├── memoizer.ts │ │ │ └── value.ts │ │ ├── comparer.ts │ │ ├── components │ │ │ └── IsolatedInput │ │ │ │ └── index.tsx │ │ ├── debounce.ts │ │ ├── environment │ │ │ └── index.ts │ │ ├── generic.ts │ │ ├── math │ │ │ ├── arrayZipMap.ts │ │ │ ├── matrixZipMap.ts │ │ │ └── random.ts │ │ ├── memoizer.ts │ │ ├── objPropsToCamel.ts │ │ ├── sorting │ │ │ ├── index.ts │ │ │ ├── multi.ts │ │ │ └── single.ts │ │ ├── storage │ │ │ └── Cookie.ts │ │ ├── syntax-tree │ │ │ ├── index.ts │ │ │ ├── lexer.ts │ │ │ ├── lexicon.ts │ │ │ └── syntaxer.ts │ │ └── type │ │ │ └── index.ts │ ├── dash-table │ │ ├── LazyLoader.ts │ │ ├── components │ │ │ ├── Cell │ │ │ │ ├── index.tsx │ │ │ │ └── props.ts │ │ │ ├── CellDropdown │ │ │ │ └── index.tsx │ │ │ ├── CellFactory.tsx │ │ │ ├── CellInput │ │ │ │ └── index.tsx │ │ │ ├── CellLabel │ │ │ │ └── index.tsx │ │ │ ├── CellMarkdown │ │ │ │ └── index.tsx │ │ │ ├── ControlledTable │ │ │ │ ├── fragments │ │ │ │ │ └── TableTooltip.tsx │ │ │ │ └── index.tsx │ │ │ ├── EdgeFactory.tsx │ │ │ ├── Export │ │ │ │ ├── index.tsx │ │ │ │ └── utils.tsx │ │ │ ├── Filter │ │ │ │ ├── Advanced.tsx │ │ │ │ ├── Column.tsx │ │ │ │ └── FilterOptions.tsx │ │ │ ├── FilterFactory.tsx │ │ │ ├── HeaderFactory.tsx │ │ │ ├── PageNavigation │ │ │ │ ├── index.tsx │ │ │ │ └── props.ts │ │ │ ├── Table │ │ │ │ ├── Dropdown.css │ │ │ │ ├── Table.less │ │ │ │ ├── controlledPropsHelper.ts │ │ │ │ ├── derivedPropsHelper.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── props.ts │ │ │ │ ├── shouldComponentUpdate.ts │ │ │ │ └── style.ts │ │ │ ├── Tooltip │ │ │ │ └── index.tsx │ │ │ ├── dropdownHelper.ts │ │ │ └── tooltipHelper.ts │ │ ├── conditional │ │ │ └── index.ts │ │ ├── dash │ │ │ ├── DataTable.js │ │ │ ├── Sanitizer.ts │ │ │ ├── fragments │ │ │ │ └── DataTable.js │ │ │ └── validate.ts │ │ ├── derived │ │ │ ├── cell │ │ │ │ ├── cellProps.ts │ │ │ │ ├── contents.tsx │ │ │ │ ├── dropdowns.ts │ │ │ │ ├── eventHandlerProps.ts │ │ │ │ ├── isActive.ts │ │ │ │ ├── isSelected.ts │ │ │ │ ├── operations.tsx │ │ │ │ ├── resolveFlag.ts │ │ │ │ ├── wrapperStyles.ts │ │ │ │ └── wrappers.tsx │ │ │ ├── data │ │ │ │ ├── viewport.ts │ │ │ │ ├── virtual.ts │ │ │ │ └── virtualized.ts │ │ │ ├── edges │ │ │ │ ├── data.ts │ │ │ │ ├── filter.ts │ │ │ │ ├── header.ts │ │ │ │ ├── index.ts │ │ │ │ ├── operationOfData.ts │ │ │ │ ├── operationOfFilters.ts │ │ │ │ ├── operationOfHeaders.ts │ │ │ │ └── type.ts │ │ │ ├── filter │ │ │ │ ├── map.ts │ │ │ │ └── wrapperStyles.ts │ │ │ ├── header │ │ │ │ ├── columnFlag.ts │ │ │ │ ├── content.tsx │ │ │ │ ├── fixedHeaders.ts │ │ │ │ ├── headerRows.ts │ │ │ │ ├── indices.ts │ │ │ │ ├── labels.ts │ │ │ │ ├── labelsAndIndices.ts │ │ │ │ ├── operations.tsx │ │ │ │ ├── wrapperStyles.ts │ │ │ │ └── wrappers.tsx │ │ │ ├── paginator.ts │ │ │ ├── selects │ │ │ │ ├── columns.ts │ │ │ │ └── rows.ts │ │ │ ├── style │ │ │ │ ├── IStyle.ts │ │ │ │ ├── cssProperties.ts │ │ │ │ ├── index.ts │ │ │ │ ├── props.ts │ │ │ │ └── py2jsCssProperties.ts │ │ │ └── table │ │ │ │ ├── data_loading.ts │ │ │ │ ├── fragmentStyles.ts │ │ │ │ ├── fragments.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── tooltip.ts │ │ ├── handlers │ │ │ └── cellEvents.ts │ │ ├── index.ts │ │ ├── style │ │ │ └── reset.less │ │ ├── syntax-tree │ │ │ ├── MultiColumnsSyntaxTree.ts │ │ │ ├── QuerySyntaxTree.ts │ │ │ ├── SingleColumnSyntaxTree.ts │ │ │ ├── index.ts │ │ │ ├── lexeme │ │ │ │ ├── block.ts │ │ │ │ ├── expression.ts │ │ │ │ ├── logical.ts │ │ │ │ ├── relational.ts │ │ │ │ └── unary.ts │ │ │ └── lexicon │ │ │ │ ├── column.ts │ │ │ │ ├── columnMulti.ts │ │ │ │ ├── index.ts │ │ │ │ └── query.ts │ │ ├── tooltips │ │ │ └── props.ts │ │ ├── type │ │ │ ├── any.ts │ │ │ ├── date.ts │ │ │ ├── formatter.ts │ │ │ ├── null.ts │ │ │ ├── number.ts │ │ │ ├── reconcile.ts │ │ │ └── text.ts │ │ └── utils │ │ │ ├── Markdown.ts │ │ │ ├── TableClipboardHelper.ts │ │ │ ├── actions.js │ │ │ ├── applyClipboardToData.ts │ │ │ ├── generate.ts │ │ │ ├── navigation.ts │ │ │ └── unicode.ts │ └── third-party │ │ └── highlight.js │ ├── tests │ ├── __init__.py │ ├── assets │ │ ├── 16zpallagi-25cols-100klines.csv │ │ └── gapminder.csv │ ├── js-unit │ │ ├── clipboard_test.ts │ │ ├── dash_table_queries_test.ts │ │ ├── dateCoercion_test.ts │ │ ├── dateValidation_test.ts │ │ ├── derivedFragmentStyles_test.ts │ │ ├── derivedSelectedRows_test.ts │ │ ├── derivedViewport_test.ts │ │ ├── edges_test.ts │ │ ├── editColumnNames.ts │ │ ├── exportUtils_tests.ts │ │ ├── formatting_test.ts │ │ ├── isEditable_test.ts │ │ ├── lexeme_test.ts │ │ ├── loadingState.ts │ │ ├── multi_columns_syntactic_tree.ts │ │ ├── numberCoercion_test.ts │ │ ├── numberValidation_test.ts │ │ ├── query_syntactic_tree_test.ts │ │ ├── reconcile_test.ts │ │ ├── single_column_syntactic_tree_test.ts │ │ ├── sorting_test.ts │ │ ├── table_clipboard_helper_test.ts │ │ ├── table_update_test.ts │ │ ├── textCoercion_test.ts │ │ └── textValidation_test.ts │ ├── selenium │ │ ├── assets │ │ │ ├── logo.png │ │ │ └── solar.csv │ │ ├── conftest.py │ │ ├── test_basic_copy_paste.py │ │ ├── test_basic_operations.py │ │ ├── test_bootstrap.py │ │ ├── test_column.py │ │ ├── test_derived_props.py │ │ ├── test_dropdown.py │ │ ├── test_edit.py │ │ ├── test_editable.py │ │ ├── test_empty.py │ │ ├── test_export.py │ │ ├── test_filter.py │ │ ├── test_filter2.py │ │ ├── test_formatting.py │ │ ├── test_header.py │ │ ├── test_markdown.py │ │ ├── test_markdown_assets │ │ │ ├── logo.png │ │ │ └── scripts.js │ │ ├── test_markdown_copy_paste.py │ │ ├── test_markdown_html.py │ │ ├── test_markdown_link.py │ │ ├── test_multiple_tables.py │ │ ├── test_navigation.py │ │ ├── test_navigation_keyboard.py │ │ ├── test_navigation_keyboard_readonly.py │ │ ├── test_navigation_mouse.py │ │ ├── test_pagination.py │ │ ├── test_readonly_cell.py │ │ ├── test_scrolling.py │ │ ├── test_scrolling2.py │ │ ├── test_sizing.py │ │ ├── test_sizing_a.py │ │ ├── test_sizing_b.py │ │ ├── test_sizing_c.py │ │ ├── test_sizing_d.py │ │ ├── test_sizing_e.py │ │ ├── test_sizing_x.py │ │ ├── test_sizing_y.py │ │ ├── test_sizing_z.py │ │ ├── test_sort.py │ │ ├── test_tooltip.py │ │ ├── test_typed.py │ │ └── utils.py │ ├── unit │ │ └── format_test.py │ └── visual │ │ └── percy-storybook │ │ ├── @Types │ │ └── modules.d.ts │ │ ├── Border.defaults.percy.tsx │ │ ├── Border.style.percy.tsx │ │ ├── Css.percy.tsx │ │ ├── DashTable.percy.tsx │ │ ├── Dropdown.percy.tsx │ │ ├── Filters.percy.tsx │ │ ├── Header.actions.percy.tsx │ │ ├── Header.percy.tsx │ │ ├── Hideable.percy.tsx │ │ ├── MarkdownCells.percy.tsx │ │ ├── Multiline.percy.tsx │ │ ├── Sizing.percy.tsx │ │ ├── Style.percy.tsx │ │ ├── TriadValidation.percy.tsx │ │ ├── Types.percy.tsx │ │ ├── Virtualization.percy.tsx │ │ ├── Width.all.percy.tsx │ │ ├── Width.empty.percy.tsx │ │ ├── fixtures.ts │ │ └── tsconfig.json │ ├── tsconfig.base.json │ ├── tsconfig.json │ ├── tsconfig.lint.json │ ├── webpack.config.js │ ├── webpack.dev.config.js │ ├── webpack.serve.config.js │ └── webpack.test.config.js ├── dash ├── __init__.py ├── _callback.py ├── _callback_context.py ├── _configs.py ├── _dash_renderer.py ├── _get_app.py ├── _get_paths.py ├── _grouping.py ├── _hooks.py ├── _jupyter.py ├── _obsolete.py ├── _pages.py ├── _patch.py ├── _utils.py ├── _validate.py ├── _watch.py ├── background_callback │ ├── __init__.py │ ├── _proxy_set_props.py │ └── managers │ │ ├── __init__.py │ │ ├── celery_manager.py │ │ └── diskcache_manager.py ├── dash-renderer │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .npmignore │ ├── @Types │ │ └── modules.d.ts │ ├── MANIFEST.in │ ├── babel.config.js │ ├── config │ │ └── eslint │ │ │ └── eslintrc-node.json │ ├── index.html │ ├── init.template │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── renderer-test.sh │ ├── setup.py │ ├── src │ │ ├── APIController.react.js │ │ ├── AccessDenied.react.js │ │ ├── AppContainer.react.js │ │ ├── AppProvider.react.tsx │ │ ├── DashRenderer.js │ │ ├── StoreObserver.ts │ │ ├── actions │ │ │ ├── api.js │ │ │ ├── callbacks.ts │ │ │ ├── constants.js │ │ │ ├── dependencies.js │ │ │ ├── dependencies_ts.ts │ │ │ ├── index.js │ │ │ ├── isAppReady.js │ │ │ ├── isLoading.ts │ │ │ ├── loading.ts │ │ │ ├── patch.ts │ │ │ ├── paths.js │ │ │ ├── patternMatching.ts │ │ │ ├── requestDependencies.ts │ │ │ └── utils.js │ │ ├── checkPropTypes.js │ │ ├── components │ │ │ ├── core │ │ │ │ ├── Loading.react.js │ │ │ │ ├── Reloader.react.js │ │ │ │ ├── Toolbar.css │ │ │ │ └── Toolbar.react.js │ │ │ └── error │ │ │ │ ├── CallbackGraph │ │ │ │ ├── CallbackGraphContainer.css │ │ │ │ ├── CallbackGraphContainer.react.js │ │ │ │ ├── CallbackGraphContainerStylesheet.js │ │ │ │ └── CallbackGraphEffects.js │ │ │ │ ├── ComponentErrorBoundary.react.js │ │ │ │ ├── FrontEnd │ │ │ │ ├── FrontEndError.css │ │ │ │ ├── FrontEndError.react.js │ │ │ │ └── FrontEndErrorContainer.react.js │ │ │ │ ├── GlobalErrorContainer.react.js │ │ │ │ ├── GlobalErrorContainerPassthrough.react.js │ │ │ │ ├── Percy.css │ │ │ │ ├── icons │ │ │ │ ├── BellIcon.svg │ │ │ │ ├── CheckIcon.svg │ │ │ │ ├── ClockIcon.svg │ │ │ │ ├── CollapseIcon.svg │ │ │ │ ├── DebugIcon.svg │ │ │ │ ├── ErrorIcon.svg │ │ │ │ ├── Expand.svg │ │ │ │ ├── GraphIcon.svg │ │ │ │ ├── LeftArrow.svg │ │ │ │ ├── OffIcon.svg │ │ │ │ ├── ReloadIcon.svg │ │ │ │ └── RightArrow.svg │ │ │ │ ├── menu │ │ │ │ ├── DebugMenu.css │ │ │ │ ├── DebugMenu.react.js │ │ │ │ ├── VersionInfo.css │ │ │ │ └── VersionInfo.react.js │ │ │ │ └── werkzeugcss.js │ │ ├── config.ts │ │ ├── constants │ │ │ └── constants.js │ │ ├── dashApi.ts │ │ ├── exceptions.js │ │ ├── index.js │ │ ├── isSimpleComponent.js │ │ ├── observers │ │ │ ├── documentTitle.ts │ │ │ ├── executedCallbacks.ts │ │ │ ├── executingCallbacks.ts │ │ │ ├── isLoading.ts │ │ │ ├── prioritizedCallbacks.ts │ │ │ ├── requestedCallbacks.ts │ │ │ └── storedCallbacks.ts │ │ ├── persistence.js │ │ ├── reducers │ │ │ ├── api.js │ │ │ ├── appLifecycle.js │ │ │ ├── callbackJobs.ts │ │ │ ├── callbacks.ts │ │ │ ├── changed.js │ │ │ ├── config.js │ │ │ ├── constants.js │ │ │ ├── dependencyGraph.js │ │ │ ├── error.js │ │ │ ├── history.js │ │ │ ├── hooks.js │ │ │ ├── isLoading.ts │ │ │ ├── layout.js │ │ │ ├── loading.ts │ │ │ ├── paths.js │ │ │ ├── profile.js │ │ │ └── reducer.js │ │ ├── registry.js │ │ ├── store.ts │ │ ├── styles │ │ │ └── styles.js │ │ ├── types │ │ │ ├── callbacks.ts │ │ │ └── component.ts │ │ ├── utils │ │ │ ├── callbacks.ts │ │ │ ├── clientsideFunctions.ts │ │ │ ├── libraries.ts │ │ │ ├── stores.ts │ │ │ └── wait.ts │ │ └── wrapper │ │ │ ├── CheckedComponent.tsx │ │ │ ├── DashContext.tsx │ │ │ ├── DashWrapper.tsx │ │ │ ├── ExternalWrapper.tsx │ │ │ ├── selectors.ts │ │ │ └── wrapping.ts │ ├── tests │ │ ├── isAppReady.test.js │ │ └── persistence.test.js │ ├── tsconfig.json │ ├── tslint.json │ ├── webpack.base.config.js │ ├── webpack.config.js │ └── webpack.test.config.js ├── dash.py ├── dash_table │ └── .gitkeep ├── dcc │ └── .gitkeep ├── dependencies.py ├── development │ ├── __init__.py │ ├── _all_keywords.py │ ├── _collect_nodes.py │ ├── _generate_prop_types.py │ ├── _jl_components_generation.py │ ├── _py_components_generation.py │ ├── _py_prop_typing.py │ ├── _r_components_generation.py │ ├── base_component.py │ ├── build_process.py │ ├── component_generator.py │ └── update_components.py ├── exceptions.py ├── extract-meta.js ├── favicon.ico ├── fingerprint.py ├── html │ └── .gitkeep ├── labextension │ └── package.json ├── nbextension │ ├── README.md │ ├── __init__.py │ ├── dash.json │ ├── description.yaml │ └── main.js ├── py.typed ├── renovate.json ├── resources.py ├── testing │ ├── __init__.py │ ├── application_runners.py │ ├── browser.py │ ├── composite.py │ ├── consts.py │ ├── dash_page.py │ ├── errors.py │ ├── newhooks.py │ ├── plugin.py │ └── wait.py ├── types.py └── version.py ├── lerna.json ├── package-lock.json ├── package.json ├── pytest.ini ├── requirements ├── celery.txt ├── ci.txt ├── compress.txt ├── dev.txt ├── diskcache.txt ├── install.txt └── testing.txt ├── setup.py └── tests ├── __init__.py ├── assets ├── __init__.py ├── grouping_app.py ├── simple_app.py └── todo_app.py ├── background_callback ├── __init__.py ├── app1.py ├── app2.py ├── app3.py ├── app4.py ├── app5.py ├── app6.py ├── app7.py ├── app_arbitrary.py ├── app_bg_on_error.py ├── app_callback_ctx.py ├── app_ctx_cookies.py ├── app_diff_outputs.py ├── app_error.py ├── app_page_cancel.py ├── app_pattern_matching.py ├── app_progress_delete.py ├── app_short_interval.py ├── app_side_update.py ├── app_unordered.py ├── conftest.py ├── test_basic_long_callback001.py ├── test_basic_long_callback002.py ├── test_basic_long_callback003.py ├── test_basic_long_callback004.py ├── test_basic_long_callback005.py ├── test_basic_long_callback006.py ├── test_basic_long_callback007.py ├── test_basic_long_callback008.py ├── test_basic_long_callback009.py ├── test_basic_long_callback010.py ├── test_basic_long_callback011.py ├── test_basic_long_callback012.py ├── test_basic_long_callback013.py ├── test_basic_long_callback014.py ├── test_basic_long_callback015.py ├── test_basic_long_callback016.py ├── test_basic_long_callback017.py ├── test_basic_long_callback018.py ├── test_ctx_cookies.py └── utils.py ├── compliance └── test_typing.py ├── conftest.py ├── integration ├── __init__.py ├── callbacks │ ├── __init__.py │ ├── state_path.json │ ├── test_arbitrary_callbacks.py │ ├── test_basic_callback.py │ ├── test_callback_context.py │ ├── test_callback_error.py │ ├── test_callback_optional.py │ ├── test_dynamic_callback.py │ ├── test_global_dash_callback.py │ ├── test_layout_paths_with_callbacks.py │ ├── test_malformed_request.py │ ├── test_missing_inputs.py │ ├── test_missing_outputs.py │ ├── test_multiple_callbacks.py │ ├── test_prevent_initial.py │ ├── test_prevent_update.py │ ├── test_validation.py │ └── test_wildcards.py ├── clientside │ ├── assets │ │ ├── clientside.js │ │ ├── clientside.mjs │ │ ├── clientsideModule.mjs │ │ └── ramda-0.25.0.min.js │ ├── test_clientside.py │ ├── test_clientside_functions.py │ ├── test_clientside_outputs_list.py │ └── test_clientside_restarts.py ├── dash │ ├── dash_import_test.py │ └── org.py ├── dash_assets │ ├── assets │ │ ├── load_first.js │ │ ├── load_ignored.js │ │ ├── nested_css │ │ │ └── nested.css │ │ ├── nested_js │ │ │ ├── load_after.js │ │ │ ├── load_after1.js │ │ │ ├── load_after10.js │ │ │ ├── load_after11.js │ │ │ ├── load_after2.js │ │ │ ├── load_after3.js │ │ │ ├── load_after4.js │ │ │ └── load_last.js │ │ └── reset.css │ └── test_dash_assets.py ├── devtools │ ├── __init__.py │ ├── hr_assets │ │ ├── hot_reload.css │ │ └── hot_reload.js │ ├── test_callback_timing.py │ ├── test_callback_validation.py │ ├── test_devtools_error_handling.py │ ├── test_devtools_ui.py │ ├── test_hot_reload.py │ └── test_props_check.py ├── multi_page │ ├── assets │ │ ├── app.jpeg │ │ ├── birds.jpeg │ │ ├── home.jpeg │ │ └── logo.jpeg │ ├── pages │ │ ├── .no_import.py │ │ ├── .no_import │ │ │ └── no_import.py │ │ ├── __init__.py │ │ ├── _no_import.py │ │ ├── defaults.py │ │ ├── metas.py │ │ ├── not_found_404.py │ │ ├── page1.py │ │ ├── page2.py │ │ ├── path_variables.py │ │ ├── query_string.py │ │ └── redirect.py │ ├── pages_error │ │ ├── __init__.py │ │ └── no_layout_page.py │ ├── test_pages_layout.py │ ├── test_pages_order.py │ └── test_pages_relative_path.py ├── renderer │ ├── initial_state_dash_app_content.html │ ├── test_add_receive_props.py │ ├── test_array_of_exact_or_shape_with_node_prop_assign_none.py │ ├── test_children_reorder.py │ ├── test_component_as_prop.py │ ├── test_dependencies.py │ ├── test_descendant_listening.py │ ├── test_due_diligence.py │ ├── test_external_component.py │ ├── test_iframe.py │ ├── test_loading_states.py │ ├── test_multi_output.py │ ├── test_persistence.py │ ├── test_race_conditions.py │ ├── test_redraw.py │ ├── test_render_type.py │ ├── test_request_hooks.py │ └── test_state_and_input.py ├── security │ ├── test_injection.py │ └── test_xss.py ├── test_csp.py ├── test_duo.py ├── test_generation.py ├── test_hooks.py ├── test_integration.py ├── test_legacy_components.py ├── test_pages_redirect_home.py ├── test_patch.py ├── test_scripts.py └── utils.py └── unit ├── development ├── TestReactComponent.react.js ├── TestReactComponentRequired.react.js ├── __init__.py ├── conftest.py ├── flow_metadata_test.json ├── metadata_required_test.json ├── metadata_test.json ├── metadata_test.py ├── test_base_component.py ├── test_collect_nodes.py ├── test_flow_metadata_conversions.py ├── test_generate_class.py ├── test_generate_class_file.py ├── test_metadata_conversions.py └── test_r_component_gen.py ├── library ├── fixtures.py ├── test_async_resources.py ├── test_background_callback_validation.py ├── test_grouped_callbacks.py ├── test_grouping.py ├── test_utils.py └── test_validate.py ├── pages ├── __init__.py ├── custom_pages │ ├── __init__.py │ └── page.py ├── sub_dir │ ├── __init__.py │ └── custom_pages │ │ ├── __init__.py │ │ └── page.py ├── test_pages.py └── test_pages_config.py ├── test_app_runners.py ├── test_browser.py ├── test_configs.py ├── test_fingerprint.py ├── test_patch.py ├── test_resources.py └── test_testing.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # Unix-style newlines with a newline ending every file 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | # Matches multiple files with brace expansion notation 9 | # Set default charset 10 | [*.{js,py}] 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 4 14 | 15 | # Matches the exact files either package.json or .circleci/config.yml 16 | [{package.json,.circleci/config.yml}] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = C901, E203, E266, E501, E731, W503 3 | select = B,C,E,F,W,T4 4 | per-file-ignores = 5 | tests/*: E722, F811 6 | dash/html/I.py: E742 7 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence 3 | * @T4rk1n @ndrezn @gvwilson @emilykl 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: plotly 2 | custom: https://plotly.com/products/consulting-and-oem/ 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature Request]" 5 | labels: 'Type: Enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Thanks so much for your interest in Dash! 11 | 12 | Before posting an issue here, please check the Dash [community forum](https://community.plotly.com/c/dash) to see if the topic has already been discussed. The community forum is also great for implementation questions. When in doubt, please feel free to just post the issue here :) 13 | 14 | **Is your feature request related to a problem? Please describe.** 15 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 16 | 17 | **Describe the solution you'd like** 18 | A clear and concise description of what you want to happen. 19 | 20 | **Describe alternatives you've considered** 21 | A clear and concise description of any alternative solutions or features you've considered. 22 | 23 | **Additional context** 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | *Start with a description of this PR. Then edit the list below to the items that make sense for your PR scope, and check off the boxes as you go!* 2 | 3 | ## Contributor Checklist 4 | 5 | - [ ] I have broken down my PR scope into the following TODO tasks 6 | - [ ] task 1 7 | - [ ] task 2 8 | - [ ] I have run the tests locally and they passed. (refer to testing section in [contributing](https://github.com/plotly/dash/blob/master/CONTRIBUTING.md)) 9 | - [ ] I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR 10 | 11 | ### optionals 12 | 13 | - [ ] I have added entry in the `CHANGELOG.md` 14 | - [ ] If this PR needs a follow-up in **dash docs**, **community thread**, I have mentioned the relevant URLS as follows 15 | - [ ] this GitHub [#PR number]() updates the dash docs 16 | - [ ] here is the show and tell thread in Plotly Dash community 17 | -------------------------------------------------------------------------------- /.github/workflows/update-html.yml: -------------------------------------------------------------------------------- 1 | name: update-html 2 | run-name: Update dash html components attributes 3 | on: 4 | schedule: 5 | - cron: 10 0 1 * * 6 | workflow_dispatch: 7 | inputs: 8 | name: 9 | description: Name of the run 10 | required: false 11 | type: string 12 | 13 | jobs: 14 | update-attributes: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | ref: dev 20 | - uses: actions/setup-node@v3 21 | - name: Extract elements 22 | working-directory: ./components/dash-html-components 23 | run: | 24 | npm ci 25 | npm run extract 26 | - name: Create Pull Request 27 | uses: peter-evans/create-pull-request@v5 28 | with: 29 | commit-message: Update Dash HTML elements & attributes. 30 | body: Automated HTML attributes update. 31 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run lint && \ 2 | (cd components/dash-core-components && npm run lint) && \ 3 | (cd components/dash-table && npm run lint) 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/iron 2 | -------------------------------------------------------------------------------- /@plotly/dash-component-plugins/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/preset-env', 4 | '@babel/preset-react' 5 | ] 6 | }; 7 | -------------------------------------------------------------------------------- /@plotly/dash-component-plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plotly/dash-component-plugins", 3 | "version": "1.2.3", 4 | "description": "Plugins for Dash Components", 5 | "repository": { 6 | "type": "git", 7 | "url": "git@github.com:plotly/dash.git" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/plotly/dash/issues" 11 | }, 12 | "homepage": "https://github.com/plotly/dash", 13 | "main": "dist/index.js", 14 | "scripts": { 15 | "build": "webpack" 16 | }, 17 | "author": "Marc-André Rivet", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@babel/core": "^7.19.6", 21 | "@babel/preset-env": "^7.19.4", 22 | "@babel/preset-react": "^7.18.6", 23 | "babel-loader": "^8.2.5", 24 | "react": "^16.8.6", 25 | "webpack": "^5.76.1", 26 | "webpack-cli": "^4.10.0" 27 | }, 28 | "files": [ 29 | "dist/index.js", 30 | "dist/index.js.LICENSE.txt" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /@plotly/dash-component-plugins/src/History.js: -------------------------------------------------------------------------------- 1 | const ON_CHANGE = '_dashprivate_historychange'; 2 | 3 | export default class History { 4 | static dispatchChangeEvent() { 5 | window.dispatchEvent(new CustomEvent(ON_CHANGE)); 6 | } 7 | 8 | static onChange(listener) { 9 | window.addEventListener(ON_CHANGE, listener); 10 | 11 | return () => window.removeEventListener(ON_CHANGE, listener); 12 | } 13 | } -------------------------------------------------------------------------------- /@plotly/dash-component-plugins/src/dynamicImport.js: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react'; 2 | 3 | export const asyncDecorator = (target, promise) => { 4 | let resolve; 5 | const isReady = new Promise(r => { 6 | resolve = r; 7 | }); 8 | 9 | const state = { 10 | isReady, 11 | get: lazy(() => { 12 | return Promise.resolve(promise()).then(res => { 13 | setTimeout(async () => { 14 | await resolve(true); 15 | state.isReady = true; 16 | }, 0); 17 | 18 | return res; 19 | }); 20 | }), 21 | }; 22 | 23 | Object.defineProperty(target, '_dashprivate_isLazyComponentReady', { 24 | get: () => state.isReady 25 | }); 26 | 27 | return state.get; 28 | }; 29 | 30 | export const inheritAsyncDecorator = (target, source) => { 31 | Object.defineProperty(target, '_dashprivate_isLazyComponentReady', { 32 | get: () => isReady(source) 33 | }); 34 | } 35 | 36 | export const isReady = target => target && 37 | target._dashprivate_isLazyComponentReady; 38 | -------------------------------------------------------------------------------- /@plotly/dash-component-plugins/src/index.js: -------------------------------------------------------------------------------- 1 | import { asyncDecorator, inheritAsyncDecorator, isReady } from './dynamicImport'; 2 | import History from './History'; 3 | 4 | export { asyncDecorator, inheritAsyncDecorator, isReady }; 5 | export { History }; -------------------------------------------------------------------------------- /@plotly/dash-component-plugins/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: './src/index.js', 5 | mode: 'production', 6 | output: { 7 | path: path.resolve(__dirname, `./dist`), 8 | filename: 'index.js', 9 | library: {name: `dash-component-plugins`, type: 'umd' }, 10 | }, 11 | externals: { 12 | react: { 13 | root: 'React', 14 | commonjs2: 'react', 15 | commonjs: 'react', 16 | amd: 'react' 17 | } 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.js$/, 23 | use: { 24 | loader: 'babel-loader' 25 | } 26 | } 27 | ] 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dash_generator_test_component_nested/** 2 | include dash_generator_test_component_nested/nested/** 3 | include package.json -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/README.md: -------------------------------------------------------------------------------- 1 | Empty -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | module.exports = { presets }; 7 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/base/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os as _os 3 | 4 | _basepath = _os.path.dirname(__file__) 5 | _filepath = _os.path.abspath(_os.path.join(_basepath, 'package.json')) 6 | with open(_filepath) as f: 7 | package = json.load(f) 8 | 9 | package_name = package['name'].replace(' ', '_').replace('-', '_') 10 | __version__ = package['version'] 11 | 12 | from ._imports_ import * # noqa: F401, F403 13 | from ._imports_ import __all__ # noqa: E402 14 | 15 | _js_dist = [ 16 | dict( 17 | relative_package_path='nested/dash_generator_test_component_nested.js', 18 | namespace='dash_generator_test_component_nested' 19 | ) 20 | ] 21 | 22 | for _component in __all__: 23 | setattr(locals()[_component], '_js_dist', _js_dist) 24 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import json 3 | 4 | with open('package.json') as f: 5 | package = json.load(f) 6 | 7 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 8 | 9 | setup( 10 | name=package_name, 11 | version=package["version"], 12 | author=package['author'], 13 | author_email='chris@plotly.com', 14 | packages=[package_name], 15 | include_package_data=True, 16 | license=package['license'], 17 | description=package.get("description", package_name), 18 | install_requires=[] 19 | ) 20 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/src/components/MyNestedComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | /** 5 | * MyNestedComponent description 6 | */ 7 | const MyNestedComponent = ({ id, value = '' }) => (
{value}
); 8 | 9 | MyNestedComponent.propTypes = { 10 | /** 11 | * The id of the component 12 | */ 13 | id: PropTypes.string, 14 | 15 | /** 16 | * The value to display 17 | */ 18 | value: PropTypes.string 19 | }; 20 | 21 | export default MyNestedComponent; -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/src/index.js: -------------------------------------------------------------------------------- 1 | import MyNestedComponent from './components/MyNestedComponent'; 2 | 3 | export { 4 | MyNestedComponent, 5 | }; 6 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-nested/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | const packagejson = require('./package.json'); 5 | 6 | const dashLibraryName = packagejson.name.replace(/-/g, '_'); 7 | 8 | module.exports = { 9 | entry: { main: './src/index.js' }, 10 | externals: { 11 | react: 'React', 12 | 'react-dom': 'ReactDOM', 13 | 'prop-types': 'PropTypes' 14 | }, 15 | output: { 16 | path: path.resolve(__dirname, dashLibraryName, 'nested'), 17 | filename: `${dashLibraryName}.js`, 18 | library: { 19 | name: dashLibraryName, 20 | type: 'window', 21 | } 22 | }, 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.jsx?$/, 27 | exclude: /node_modules/, 28 | use: { 29 | loader: 'babel-loader' 30 | } 31 | } 32 | ], 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dash_generator_test_component_standard/** 2 | include package.json -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/README.md: -------------------------------------------------------------------------------- 1 | Empty -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | module.exports = { presets }; 7 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/base/godfather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/@plotly/dash-generator-test-component-standard/base/godfather.ttf -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/base/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'godfather'; 3 | src: url(./godfather.ttf) format('truetype'); 4 | } -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import json 3 | 4 | with open('package.json') as f: 5 | package = json.load(f) 6 | 7 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 8 | 9 | setup( 10 | name=package_name, 11 | version=package["version"], 12 | author=package['author'], 13 | author_email='chris@plotly.com', 14 | packages=[package_name], 15 | include_package_data=True, 16 | license=package['license'], 17 | description=package.get("description", package_name), 18 | install_requires=[] 19 | ) 20 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/src/components/MyStandardComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | /** 5 | * MyComponent description 6 | */ 7 | const MyStandardComponent = ({ id, style, value = '' }) => (
{value}
); 8 | 9 | MyStandardComponent.propTypes = { 10 | /** 11 | * The id of the component 12 | */ 13 | id: PropTypes.string, 14 | 15 | /** 16 | * The style 17 | */ 18 | style: PropTypes.shape, 19 | 20 | /** 21 | * The value to display 22 | */ 23 | value: PropTypes.string 24 | }; 25 | 26 | export default MyStandardComponent; 27 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/src/index.js: -------------------------------------------------------------------------------- 1 | import MyStandardComponent from './components/MyStandardComponent'; 2 | 3 | export { 4 | MyStandardComponent, 5 | }; 6 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-standard/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | const packagejson = require('./package.json'); 5 | 6 | const dashLibraryName = packagejson.name.replace(/-/g, '_'); 7 | 8 | module.exports = { 9 | entry: { main: './src/index.js' }, 10 | externals: { 11 | react: 'React', 12 | 'react-dom': 'ReactDOM', 13 | 'prop-types': 'PropTypes' 14 | }, 15 | output: { 16 | path: path.resolve(__dirname, dashLibraryName), 17 | filename: `${dashLibraryName}.js`, 18 | library: { 19 | name: dashLibraryName, 20 | type: 'window', 21 | } 22 | }, 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.jsx?$/, 27 | exclude: /node_modules/, 28 | use: { 29 | loader: 'babel-loader' 30 | } 31 | } 32 | ], 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/README.md: -------------------------------------------------------------------------------- 1 | # Dash generator test component typescript 2 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/_dash_prop_typing.py: -------------------------------------------------------------------------------- 1 | ignore_props = ['ignored_prop'] 2 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | const plugins = []; 7 | 8 | module.exports = { presets, plugins }; 9 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/base/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os as _os 3 | 4 | _basepath = _os.path.dirname(__file__) 5 | _filepath = _os.path.abspath(_os.path.join(_basepath, 'package.json')) 6 | with open(_filepath) as f: 7 | package = json.load(f) 8 | 9 | package_name = package['name'].replace(' ', '_').replace('-', '_') 10 | __version__ = package['version'] 11 | 12 | from ._imports_ import * # noqa: F401, F403 13 | from ._imports_ import __all__ # noqa: E402 14 | 15 | _js_dist = [ 16 | dict( 17 | relative_package_path='dash_generator_test_component_typescript.js', 18 | namespace='dash_generator_test_component_typescript' 19 | ), 20 | { 21 | "dev_package_path": "proptypes.js", 22 | "dev_only": True, 23 | "namespace": 'dash_generator_test_component_typescript' 24 | } 25 | ] 26 | 27 | for _component in __all__: 28 | setattr(locals()[_component], '_js_dist', _js_dist) 29 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/base/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/@plotly/dash-generator-test-component-typescript/base/py.typed -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | coverageProvider: "v8", 3 | transform: { 4 | '^.+\\.(ts|tsx)?$': 'ts-jest', 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import json 3 | 4 | with open('package.json') as f: 5 | package = json.load(f) 6 | 7 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 8 | 9 | setup( 10 | name=package_name, 11 | version=package["version"], 12 | author=package['author'], 13 | author_email='chris@plotly.com', 14 | packages=[package_name], 15 | include_package_data=True, 16 | license=package['license'], 17 | description=package.get("description", package_name), 18 | install_requires=[] 19 | ) 20 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/EmptyComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const EmptyComponent = () =>
Empty
; 4 | 5 | export default EmptyComponent; 6 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/FCComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TypescriptComponentProps } from '../props'; 3 | 4 | const FCComponent: React.FC = (props) => ( 5 |
{props.children}
6 | ); 7 | 8 | export default FCComponent; 9 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/MemoTypeScriptComponent.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {TypescriptComponentProps} from '../props'; 3 | 4 | /** 5 | * Description 6 | * Example: 7 | * ``` 8 | * @app.callback(...) 9 | * def on_click(*args): 10 | * return 1 11 | * ``` 12 | */ 13 | const MemoTypeScriptComponent = (props: TypescriptComponentProps) => ( 14 |
{props.required_string}
15 | ); 16 | 17 | export default React.memo(MemoTypeScriptComponent, () => true); 18 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/MixedComponent.tsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | type Props = { 5 | id?: string; 6 | prop: string[]; 7 | } 8 | 9 | const MixedComponent: React.FC = (props) => { 10 | return ( 11 |
{props.children}
12 | ) 13 | } 14 | 15 | MixedComponent.propTypes = { 16 | prop: PropTypes.arrayOf(PropTypes.string).isRequired 17 | } 18 | 19 | export default MixedComponent; 20 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/RequiredChildrenComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { RequiredChildrenComponentProps } from "../props"; 3 | 4 | 5 | const RequiredChildrenComponent = (props: RequiredChildrenComponentProps) => { 6 | const {children} = props; 7 | return ( 8 |
9 | {children} 10 |
11 | ) 12 | } 13 | 14 | export default RequiredChildrenComponent; 15 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/StandardComponent.react.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | 5 | const StandardComponent = (props) => { 6 | const { id, children } = props; 7 | 8 | return ( 9 |
10 | {children} 11 |
12 | ) 13 | } 14 | 15 | StandardComponent.propTypes = { 16 | id: PropTypes.string, 17 | children: PropTypes.node, 18 | } 19 | 20 | export default React.memo(StandardComponent, (prevProps,nextProps) => true) 21 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/TypeScriptClassComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {TypescriptComponentProps} from '../props'; 3 | 4 | /** 5 | * Description 6 | * Example: 7 | * ``` 8 | * @app.callback(...) 9 | * def on_click(*args): 10 | * return 1 11 | * ``` 12 | */ 13 | export default class TypeScriptClassComponent extends React.PureComponent { 14 | render() { 15 | const {required_string, id} = this.props; 16 | return ( 17 |
18 | {required_string} 19 |
20 | ); 21 | } 22 | 23 | static defaultProps = { 24 | string_default: 'default', 25 | number_default: 42, 26 | bool_default: false, 27 | null_default: null, 28 | obj_default: { 29 | a: 'a', 30 | b: 3 31 | } 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/TypeScriptComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {TypescriptComponentProps} from '../props'; 3 | 4 | /** 5 | * Component docstring 6 | */ 7 | const TypeScriptComponent = ({ 8 | required_string, 9 | id, 10 | string_default = 'default', 11 | number_default = 42, 12 | bool_default = true, 13 | null_default = null, 14 | obj_default = { a: 'a', b: 3 }, 15 | ...props 16 | }: TypescriptComponentProps) => { 17 | return
{required_string}
; 18 | }; 19 | 20 | export default TypeScriptComponent; 21 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/components/WrappedHTML.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {WrappedHTMLProps} from '../props'; 3 | 4 | /** 5 | * Component docstring 6 | */ 7 | const WrappedHTML = (props: WrappedHTMLProps) => { 8 | return null; 9 | }; 10 | 11 | export default WrappedHTML; 12 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | import TypeScriptComponent from './components/TypeScriptComponent'; 2 | import TypeScriptClassComponent from './components/TypeScriptClassComponent'; 3 | import MemoTypeScriptComponent from './components/MemoTypeScriptComponent'; 4 | import StandardComponent from './components/StandardComponent.react'; 5 | import WrappedHTML from './components/WrappedHTML'; 6 | import FCComponent from './components/FCComponent'; 7 | import EmptyComponent from './components/EmptyComponent'; 8 | import MixedComponent from './components/MixedComponent'; 9 | import RequiredChildrenComponent from './components/RequiredChildrenComponent'; 10 | 11 | export { 12 | TypeScriptComponent, 13 | TypeScriptClassComponent, 14 | MemoTypeScriptComponent, 15 | StandardComponent, 16 | WrappedHTML, 17 | FCComponent, 18 | EmptyComponent, 19 | MixedComponent, 20 | RequiredChildrenComponent, 21 | }; 22 | -------------------------------------------------------------------------------- /@plotly/dash-generator-test-component-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "baseUrl": "src/ts", 5 | "paths": { 6 | }, 7 | "inlineSources": true, 8 | "sourceMap": true, 9 | "esModuleInterop": true 10 | }, 11 | "exclude": [ 12 | "node_modules" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /@plotly/dash-jupyterlab/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } -------------------------------------------------------------------------------- /@plotly/dash-jupyterlab/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import { JupyterFrontEndPlugin } from '@jupyterlab/application'; 2 | import '../style/index.css'; 3 | /** 4 | * Initialization data for the jupyterlab-dash extension. 5 | */ 6 | declare const extension: JupyterFrontEndPlugin; 7 | export default extension; 8 | -------------------------------------------------------------------------------- /@plotly/dash-jupyterlab/style/index.css: -------------------------------------------------------------------------------- 1 | .jp-dashWidget iframe { 2 | height: 100%; 3 | width: 100%; 4 | padding: 20px; 5 | box-sizing: border-box; 6 | } 7 | -------------------------------------------------------------------------------- /@plotly/dash-jupyterlab/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "lib": ["es2018", "dom"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "noEmitOnError": true, 8 | "noUnusedLocals": true, 9 | "outDir": "lib", 10 | "rootDir": "src", 11 | "strict": true, 12 | "strictNullChecks": false, 13 | "target": "es2018", 14 | "types": [], 15 | "esModuleInterop": true 16 | }, 17 | "include": ["src/*"] 18 | } 19 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dash_test_components/** 2 | include package.json -------------------------------------------------------------------------------- /@plotly/dash-test-components/README.md: -------------------------------------------------------------------------------- 1 | Empty -------------------------------------------------------------------------------- /@plotly/dash-test-components/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | const plugins = [ 7 | '@babel/plugin-syntax-dynamic-import' 8 | ]; 9 | 10 | module.exports = { presets, plugins }; 11 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/base/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os as _os 3 | 4 | _basepath = _os.path.dirname(__file__) 5 | _filepath = _os.path.abspath(_os.path.join(_basepath, 'package.json')) 6 | with open(_filepath) as f: 7 | package = json.load(f) 8 | 9 | package_name = package['name'].replace(' ', '_').replace('-', '_') 10 | __version__ = package['version'] 11 | 12 | from ._imports_ import * # noqa: F401, F403 13 | from ._imports_ import __all__ # noqa: E402 14 | 15 | _js_dist = [ 16 | { 17 | "relative_package_path": "dash_test_components.js", 18 | "namespace": "dash_test_components" 19 | }, 20 | { 21 | "relative_package_path": "async-test-async.js", 22 | "namespace": "dash_test_components", 23 | "async": "lazy", 24 | }, 25 | ] 26 | 27 | for _component in __all__: 28 | setattr(locals()[_component], '_js_dist', _js_dist) 29 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import json 3 | 4 | with open('package.json') as f: 5 | package = json.load(f) 6 | 7 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 8 | 9 | setup( 10 | name=package_name, 11 | version=package["version"], 12 | author=package['author'], 13 | author_email='chris@plotly.com', 14 | packages=[package_name], 15 | include_package_data=True, 16 | license=package['license'], 17 | description=package.get("description", package_name), 18 | install_requires=[] 19 | ) 20 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/AddPropsComponent.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | const AddPropsComponent = (props) => { 5 | const {children, id} = props; 6 | 7 | 8 | return ( 9 |
10 | {React.cloneElement(children, { 11 | receive: `Element #${id} pass`, 12 | })} 13 |
14 | ); 15 | }; 16 | 17 | AddPropsComponent.propTypes = { 18 | id: PropTypes.string, 19 | children: PropTypes.node, 20 | }; 21 | 22 | export default AddPropsComponent; 23 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/ArrayOfExactOrShapeWithNodePropAssignNone.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const ArrayOfExactOrShapeWithNodePropAssignNone = (props) => { 5 | const { id, test_array_of_exact_prop, test_array_of_shape_prop } = props; 6 | 7 | return ( 8 |
9 | {`length of test_array_of_exact_prop: ${(test_array_of_exact_prop || []).length}, length of test_array_of_shape_prop: ${(test_array_of_shape_prop || []).length}`} 10 |
11 | ); 12 | }; 13 | 14 | ArrayOfExactOrShapeWithNodePropAssignNone.propTypes = { 15 | id: PropTypes.string, 16 | test_array_of_exact_prop: PropTypes.arrayOf( 17 | PropTypes.exact({ 18 | label: PropTypes.node, 19 | value: PropTypes.string 20 | }) 21 | ), 22 | test_array_of_shape_prop: PropTypes.arrayOf( 23 | PropTypes.shape({ 24 | label: PropTypes.node, 25 | value: PropTypes.string 26 | }) 27 | ) 28 | }; 29 | 30 | export default ArrayOfExactOrShapeWithNodePropAssignNone; 31 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/AsyncComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { Suspense } from 'react'; 3 | import { asyncDecorator } from '@plotly/dash-component-plugins'; 4 | import asyncComponentLoader from './../fragments/AsyncComponentLoader'; 5 | 6 | const AsyncComponent = props => ( 7 | 8 | ); 9 | 10 | const RealAsyncComponent = asyncDecorator(AsyncComponent, asyncComponentLoader); 11 | 12 | AsyncComponent.propTypes = { 13 | id: PropTypes.string, 14 | value: PropTypes.string 15 | }; 16 | 17 | export default AsyncComponent; -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/CollapseComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { Fragment } from 'react'; 3 | 4 | const CollapseComponent = props => ( 5 | {props.display ? props.children : null} 6 | ); 7 | 8 | CollapseComponent.propTypes = { 9 | children: PropTypes.node, 10 | display: PropTypes.bool, 11 | id: PropTypes.string 12 | }; 13 | 14 | export default CollapseComponent; 15 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/DelayedEventComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | const DelayedEventComponent = ({ id, n_clicks = 0, setProps }) => ( 12 | ; 13 | }; 14 | 15 | RenderType.propTypes = { 16 | id: PropTypes.string, 17 | dashRenderType: PropTypes.string, 18 | n_clicks: PropTypes.number, 19 | setProps: PropTypes.func 20 | }; 21 | 22 | RenderType.dashRenderType = true; 23 | export default RenderType; 24 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/StyledComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | /** 5 | * MyComponent description 6 | */ 7 | const StyledComponent = ({ id, style, value = '' }) => (
{value}
); 8 | 9 | StyledComponent.propTypes = { 10 | /** 11 | * The id of the component 12 | */ 13 | id: PropTypes.string, 14 | 15 | /** 16 | * The style 17 | */ 18 | style: PropTypes.object, 19 | 20 | /** 21 | * The value to display 22 | */ 23 | value: PropTypes.string 24 | }; 25 | 26 | export default StyledComponent; 27 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/components/WidthComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { Fragment } from 'react'; 3 | 4 | const WidthComponent = ({width = 0}) => ( 5 | {width} 6 | ); 7 | 8 | WidthComponent.propTypes = { 9 | id: PropTypes.string, 10 | width: PropTypes.number 11 | }; 12 | 13 | export default WidthComponent; 14 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/fragments/AsyncComponent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | /** 5 | * MyComponent description 6 | */ 7 | const AsyncComponent = ({ id, value }) =>
{value}
; 8 | 9 | AsyncComponent.propTypes = { 10 | id: PropTypes.string, 11 | value: PropTypes.string 12 | }; 13 | 14 | export default AsyncComponent; 15 | -------------------------------------------------------------------------------- /@plotly/dash-test-components/src/fragments/AsyncComponentLoader.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "test-async" */ './AsyncComponent'); 2 | -------------------------------------------------------------------------------- /@plotly/eslint-config-dash/.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz -------------------------------------------------------------------------------- /@plotly/eslint-config-dash/README.md: -------------------------------------------------------------------------------- 1 | # @plotly/eslint-config-dash 2 | 3 | Shareable linting configurations for Dash projects. -------------------------------------------------------------------------------- /@plotly/eslint-config-dash/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'eslint:recommended', 4 | 'prettier' 5 | ], 6 | plugins: [ 7 | 'react', 8 | 'import' 9 | ], 10 | env: { 11 | browser: true 12 | }, 13 | parser: 'babel-eslint', 14 | parserOptions: { 15 | sourceType: 'module', 16 | }, 17 | rules: { 18 | 'arrow-parens': [2, 'as-needed'], 19 | 'comma-dangle': [2, 'never'], 20 | 'no-unused-expressions': 2, 21 | 'no-unused-vars': 2, 22 | 'prefer-arrow-callback': 2, 23 | 'quote-props': [2, 'as-needed'], 24 | 'quotes': [2, 'single', { 'avoidEscape': true }] 25 | } 26 | }; -------------------------------------------------------------------------------- /@plotly/eslint-config-dash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plotly/eslint-config-dash", 3 | "version": "0.0.3", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "Marc-André Rivet", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "babel-eslint": "^10.1.0", 10 | "eslint": "^8.26.0", 11 | "eslint-config-prettier": "^8.5.0", 12 | "eslint-plugin-import": "^2.26.0", 13 | "eslint-plugin-react": "^7.31.10", 14 | "prettier": "^2.7.1" 15 | }, 16 | "peerDependencies": { 17 | "babel-eslint": "^10.1.0", 18 | "eslint": "^8.4.1", 19 | "eslint-config-prettier": "^8.3.0", 20 | "eslint-plugin-import": "^2.25.3", 21 | "eslint-plugin-react": "^7.27.1", 22 | "prettier": "^2.5.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /@plotly/prettier-config-dash/.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz -------------------------------------------------------------------------------- /@plotly/prettier-config-dash/README.md: -------------------------------------------------------------------------------- 1 | # @plotly/prettier-config-dash 2 | 3 | Shareable Prettier configuration for Dash projects. -------------------------------------------------------------------------------- /@plotly/prettier-config-dash/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 4, 3 | singleQuote: true, 4 | jsxSingleQuote: true, 5 | arrowParens: 'avoid', 6 | bracketSpacing: false, 7 | trailingComma: 'none' 8 | }; -------------------------------------------------------------------------------- /@plotly/prettier-config-dash/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plotly/prettier-config-dash", 3 | "version": "0.0.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@plotly/prettier-config-dash", 9 | "version": "0.0.1", 10 | "license": "MIT" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /@plotly/prettier-config-dash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plotly/prettier-config-dash", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "Marc-André Rivet", 7 | "license": "MIT" 8 | } 9 | -------------------------------------------------------------------------------- /@plotly/webpack-dash-dynamic-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plotly/webpack-dash-dynamic-import", 3 | "version": "1.3.0", 4 | "description": "Webpack Plugin for Dynamic Import in Dash", 5 | "repository": { 6 | "type": "git", 7 | "url": "git@github.com:plotly/dash.git" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/plotly/dash/issues" 11 | }, 12 | "homepage": "https://github.com/plotly/dash", 13 | "main": "src/index.js", 14 | "author": "Marc-André Rivet", 15 | "license": "MIT", 16 | "files": [ 17 | "/src/**" 18 | ] 19 | } -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Parmer" 5 | given-names: "Chris" 6 | - family-names: "Duval" 7 | given-names: "Philippe" 8 | - family-names: "Johnson" 9 | given-names: "Alex" 10 | orcid: https://orcid.org/0000-0003-4623-4147 11 | title: "A data and analytics web app framework for Python, no JavaScript required." 12 | version: 2.18.2 13 | doi: 10.5281/zenodo.14182630 14 | date-released: 2024-11-04 15 | url: https://github.com/plotly/dash 16 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE 3 | include requirements/*.txt 4 | include dash/favicon.ico 5 | include dash/extract-meta.js 6 | include dash/deps/*.js 7 | include dash/deps/*.map 8 | include dash/dcc/* 9 | include dash/html/* 10 | include dash/dash_table/* 11 | include dash/dash-renderer/build/*.js 12 | include dash/dash-renderer/build/*.map 13 | include dash/labextension/dist/dash-jupyterlab.tgz 14 | include dash/labextension/package.json 15 | include dash/py.typed 16 | -------------------------------------------------------------------------------- /components/dash-core-components/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # Unix-style newlines with a newline ending every file 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | # Matches multiple files with brace expansion notation 9 | # Set default charset 10 | [*.{js,py}] 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 4 14 | 15 | # Matches the exact files either package.json or .travis.yml 16 | [{package.json,.circleci/config.yml}] 17 | indent_style = space 18 | indent_size = 2 -------------------------------------------------------------------------------- /components/dash-core-components/.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | lib/ 4 | lib/bundle.js* 5 | coverage/ 6 | node_modules/ 7 | packages/ 8 | .npm 9 | vv/ 10 | venv/ 11 | *.pyc 12 | *.egg-info 13 | *.log 14 | .idea/ 15 | .DS_Store 16 | dash_core_components/ 17 | config/ 18 | -------------------------------------------------------------------------------- /components/dash-core-components/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = C901, E203, E231, E266, E501, E731, W503 3 | select = B,C,E,F,W,T4 4 | per-file-ignores = 5 | tests/*: E722, F811 -------------------------------------------------------------------------------- /components/dash-core-components/.gitignore: -------------------------------------------------------------------------------- 1 | .build_cache/ 2 | build/ 3 | dist/ 4 | lib/ 5 | lib/bundle.js* 6 | Project.toml 7 | coverage/ 8 | node_modules/ 9 | .npm 10 | vv/ 11 | venv/ 12 | .tox 13 | *.pyc 14 | *.egg-info 15 | *.log 16 | .idea/ 17 | .DS_Store 18 | 19 | /build 20 | /dash_core_components 21 | dash_core_components_base/plotly.min.js 22 | dash_core_components_base/mathjax.js 23 | /deps 24 | /inst 25 | /man 26 | /R 27 | /src/*.jl 28 | /src/jl/ 29 | DESCRIPTION 30 | NAMESPACE 31 | -------------------------------------------------------------------------------- /components/dash-core-components/.lib.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { "exclude": ["proposal-dynamic-import"] }], 4 | "@babel/preset-react" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /components/dash-core-components/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "tabWidth": 4, 4 | "singleQuote": true, 5 | "bracketSpacing": false, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /components/dash-core-components/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dash_core_components/*.js 2 | include dash_core_components/*.js.map 3 | include dash_core_components/metadata.json 4 | include dash_core_components/package-info.json 5 | include README.md 6 | include LICENSE.txt 7 | include package.json 8 | -------------------------------------------------------------------------------- /components/dash-core-components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/__init__.py -------------------------------------------------------------------------------- /components/dash-core-components/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | const plugins = [ 7 | '@babel/plugin-syntax-dynamic-import' 8 | ]; 9 | 10 | // eslint-disable-next-line no-process-env 11 | if (process.env.ENV === "test") { 12 | plugins.push("styled-jsx/babel-test"); 13 | } else { 14 | plugins.push("styled-jsx/babel"); 15 | } 16 | 17 | module.exports = { presets, plugins }; 18 | -------------------------------------------------------------------------------- /components/dash-core-components/images/upload-component.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/images/upload-component.gif -------------------------------------------------------------------------------- /components/dash-core-components/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | 16 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /components/dash-core-components/packages/README.md: -------------------------------------------------------------------------------- 1 | Folder to place temporary modules e.g. plotly.js-dist-min in .tgz format 2 | -------------------------------------------------------------------------------- /components/dash-core-components/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | junit_family = xunit1 3 | 4 | testpaths = tests/ 5 | addopts = -rsxX -vv 6 | log_format = %(asctime)s | %(levelname)s | %(name)s:%(lineno)d | %(message)s 7 | log_cli_level = ERROR 8 | -------------------------------------------------------------------------------- /components/dash-core-components/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import json 3 | 4 | with open("package.json") as f: 5 | package = json.load(f) 6 | 7 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 8 | 9 | setup( 10 | name="dash_core_components", 11 | version=package["version"], 12 | author=package["author"], 13 | author_email="chris@plotly.com", 14 | packages=[package_name], 15 | include_package_data=True, 16 | license=package["license"], 17 | description=package.get("description", package_name), 18 | install_requires=[], 19 | ) 20 | -------------------------------------------------------------------------------- /components/dash-core-components/src/components/css/Dropdown.css: -------------------------------------------------------------------------------- 1 | .dash-dropdown .Select-menu-outer { 2 | z-index: 1000; 3 | max-height: none; 4 | } 5 | 6 | .dash-dropdown .Select-menu { 7 | max-height: none; 8 | } 9 | -------------------------------------------------------------------------------- /components/dash-core-components/src/components/css/input.css: -------------------------------------------------------------------------------- 1 | input.dash-input:invalid { 2 | outline: solid red; 3 | } 4 | 5 | input.dash-input:valid { 6 | outline: none black; 7 | } 8 | -------------------------------------------------------------------------------- /components/dash-core-components/src/components/css/react-dates@20.1.0-fix.css: -------------------------------------------------------------------------------- 1 | .DateInput_input { 2 | box-sizing: border-box; 3 | } 4 | 5 | .DayPickerNavigation__verticalDefault { 6 | text-align: center; 7 | height: initial; 8 | padding: 10px 0px; 9 | } 10 | 11 | .DayPickerNavigation_svg__vertical { 12 | height: 20px; 13 | } 14 | -------------------------------------------------------------------------------- /components/dash-core-components/src/components/css/sliders.css: -------------------------------------------------------------------------------- 1 | /* Fix the default tooltip style height conflicting with the actual size of the tooltip. */ 2 | .rc-slider-tooltip-content > .rc-slider-tooltip-inner { 3 | height: unset; 4 | min-height: 20px; 5 | } 6 | -------------------------------------------------------------------------------- /components/dash-core-components/src/fragments/Graph.privateprops.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | export const privatePropTypes = { 4 | _dashprivate_transformConfig: PropTypes.func, 5 | _dashprivate_transformFigure: PropTypes.func, 6 | _dashprivate_onFigureModified: PropTypes.func, 7 | }; 8 | 9 | export const privateDefaultProps = { 10 | _dashprivate_transformConfig: c => c, 11 | _dashprivate_transformFigure: f => f, 12 | _dashprivate_onFigureModified: f => f, 13 | }; 14 | -------------------------------------------------------------------------------- /components/dash-core-components/src/fragments/Loading/spinners/DebugTitle.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function DebugTitle({id, property}) { 4 | return ( 5 |

6 | Loading #{id} 7 | 's {property} 8 |

9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/DatePickerPersistence.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | import {isNil} from 'ramda'; 3 | 4 | export default { 5 | extract: propValue => { 6 | if (!isNil(propValue)) { 7 | return moment(propValue).startOf('day').format('YYYY-MM-DD'); 8 | } 9 | return propValue; 10 | }, 11 | apply: storedValue => storedValue, 12 | }; 13 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/datePickerRange.js: -------------------------------------------------------------------------------- 1 | export default () => 2 | import(/* webpackChunkName: "datepicker" */ '../../fragments/DatePickerRange.react'); 3 | 4 | 5 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/datePickerSingle.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "datepicker" */ '../../fragments/DatePickerSingle.react'); 2 | 3 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/dropdown.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "dropdown" */ '../../fragments/Dropdown.react'); 2 | 3 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/graph.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "graph" */ '../../fragments/Graph.react'); 2 | 3 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/hljs.js: -------------------------------------------------------------------------------- 1 | export default () => Promise.resolve(window.hljs || 2 | import(/* webpackChunkName: "highlight" */ '../../third-party/highlight.js').then( 3 | result => result.default 4 | )); 5 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/markdown.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "markdown" */ '../../fragments/Markdown.react'); 2 | 3 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/mathjax.js: -------------------------------------------------------------------------------- 1 | export default (mathjax) => Promise.resolve(window.MathJax || ( 2 | mathjax === false ? 3 | undefined : 4 | import(/* webpackChunkName: "mathjax" */ '../mathjax').then(() => window.MathJax) 5 | )); 6 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/plotly.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | return Promise.resolve(window.Plotly || new Promise((resolve, reject) => { 3 | /* eslint-disable prefer-const */ 4 | let timeoutId; 5 | 6 | const element = document.createElement('script'); 7 | element.src = window._dashPlotlyJSURL; 8 | element.async = true; 9 | element.onload = () => { 10 | clearTimeout(timeoutId); 11 | resolve(); 12 | }; 13 | element.onerror = (error) => { 14 | clearTimeout(timeoutId); 15 | reject(error); 16 | }; 17 | 18 | timeoutId = setTimeout(() => { 19 | element.src = ''; 20 | reject(new Error(`plotly.js did not load after 30 seconds`)); 21 | }, 3 * 10 * 1000); 22 | 23 | document.querySelector('body').appendChild(element); 24 | })); 25 | } 26 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/rangeSlider.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "slider" */ '../../fragments/RangeSlider.react'); 2 | 3 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/slider.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "slider" */ '../../fragments/Slider.react'); 2 | 3 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LazyLoader/upload.js: -------------------------------------------------------------------------------- 1 | export default () => import(/* webpackChunkName: "upload" */ '../../fragments/Upload.react'); 2 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/LoadingElement.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * The loading element is used to add `data-dash-is-loading` attribute 5 | * on html elements. This is used to customize CSS when a component is 6 | * loading. 7 | * 8 | * See: https://dash.plotly.com/loading-states#check-loading-states-from-components 9 | */ 10 | // eslint-disable-next-line react/prop-types 11 | function LoadingElement({elementType = 'div', ...props}, ref) { 12 | const ctx = window.dash_component_api.useDashContext(); 13 | const loading = ctx.useLoading(); 14 | 15 | const givenProps = { 16 | ...props, 17 | ref, 18 | }; 19 | if (loading) { 20 | givenProps['data-dash-is-loading'] = true; 21 | } 22 | 23 | return React.createElement(elementType, givenProps); 24 | } 25 | 26 | export default React.forwardRef(LoadingElement); 27 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/MarkdownHighlighter.js: -------------------------------------------------------------------------------- 1 | import lazyhljs from './LazyLoader/hljs'; 2 | 3 | const MarkdownHighlighter = { 4 | loadhljs: function () { 5 | return lazyhljs().then(hljs => { 6 | this.hljs = hljs; 7 | this.hljsResolve(); 8 | this.isReady = true; 9 | }); 10 | }, 11 | }; 12 | 13 | const isReady = new Promise(resolve => { 14 | MarkdownHighlighter.hljsResolve = resolve; 15 | }); 16 | 17 | MarkdownHighlighter.isReady = isReady; 18 | 19 | export default MarkdownHighlighter; 20 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/computeSliderStyle.js: -------------------------------------------------------------------------------- 1 | import {memoizeWith, identity, includes} from 'ramda'; 2 | 3 | export default () => { 4 | return memoizeWith(identity, (vertical, verticalHeight, tooltip) => { 5 | const style = { 6 | padding: '25px', 7 | }; 8 | 9 | if (vertical) { 10 | style.height = verticalHeight + 'px'; 11 | 12 | if ( 13 | !tooltip || 14 | !tooltip.always_visible || 15 | !includes(tooltip.placement, [ 16 | 'left', 17 | 'topRight', 18 | 'bottomRight', 19 | ]) 20 | ) { 21 | style.paddingLeft = '0px'; 22 | } 23 | } else { 24 | if ( 25 | !tooltip || 26 | !tooltip.always_visible || 27 | !includes(tooltip.placement, ['top', 'topLeft', 'topRight']) 28 | ) { 29 | style.paddingTop = '0px'; 30 | } 31 | } 32 | 33 | return style; 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/formatSliderTooltip.js: -------------------------------------------------------------------------------- 1 | import {replace, path, split, concat, pipe} from 'ramda'; 2 | 3 | export const formatSliderTooltip = (template, value) => { 4 | return replace('{value}', value, template); 5 | }; 6 | 7 | export const transformSliderTooltip = (funcName, value) => { 8 | const func = pipe( 9 | split('.'), 10 | s => concat(['dccFunctions'], s), 11 | s => path(s, window) 12 | )(funcName); 13 | if (!func) { 14 | throw new Error( 15 | `Invalid func for slider tooltip transform: ${funcName}` 16 | ); 17 | } 18 | return func(value); 19 | }; 20 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/mathjax.js: -------------------------------------------------------------------------------- 1 | import 'mathjax/es5/tex-svg'; 2 | 3 | window.MathJax.config.startup.typeset = false; 4 | -------------------------------------------------------------------------------- /components/dash-core-components/src/utils/optionTypes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {type} from 'ramda'; 3 | 4 | export const sanitizeOptions = options => { 5 | if (type(options) === 'Object') { 6 | return Object.entries(options).map(([value, label]) => ({ 7 | label: React.isValidElement(label) ? label : String(label), 8 | value, 9 | })); 10 | } 11 | 12 | if (type(options) === 'Array') { 13 | if ( 14 | options.length > 0 && 15 | ['String', 'Number', 'Bool'].includes(type(options[0])) 16 | ) { 17 | return options.map(option => ({ 18 | label: String(option), 19 | value: option, 20 | })); 21 | } 22 | return options; 23 | } 24 | 25 | return options; 26 | }; 27 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/tests/assets/image.png -------------------------------------------------------------------------------- /components/dash-core-components/tests/assets/input.css: -------------------------------------------------------------------------------- 1 | .test-input-css input { 2 | width: 420px; 3 | border-color: hotpink; 4 | } 5 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/assets/tab.css: -------------------------------------------------------------------------------- 1 | .test-custom-tab { 2 | font-weight: bold; 3 | } 4 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/download/download-assets/chuck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/tests/integration/download/download-assets/chuck.jpg -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/dropdown/test_search_value.py: -------------------------------------------------------------------------------- 1 | from dash import Dash, Input, Output, dcc, html 2 | 3 | 4 | def test_ddsv001_search_value(dash_duo): 5 | app = Dash(__name__) 6 | app.layout = html.Div( 7 | [dcc.Dropdown(id="dropdown", search_value="something"), html.Div(id="output")] 8 | ) 9 | 10 | @app.callback( 11 | Output("output", "children"), inputs=[Input("dropdown", "search_value")] 12 | ) 13 | def update_output(search_value): 14 | return f'search_value="{search_value}"' 15 | 16 | dash_duo.start_server(app) 17 | 18 | # Get the inner input used for search value. 19 | input_ = dash_duo.find_element("#dropdown input") 20 | 21 | dash_duo.wait_for_text_to_equal("#output", 'search_value="something"') 22 | 23 | input_.send_keys("x") 24 | dash_duo.wait_for_text_to_equal("#output", 'search_value="x"') 25 | 26 | assert dash_duo.get_logs() == [] 27 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/link/test_title_prop.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from dash import Dash, Input, Output, dcc, html 3 | 4 | 5 | @pytest.mark.DCC768 6 | def test_liti001_prop(dash_dcc): 7 | app = Dash(__name__) 8 | app.layout = html.Div( 9 | [ 10 | dcc.Link( 11 | "page 1", id="link1", href="/page-1", title="This is a test title!" 12 | ), 13 | dcc.Location(id="url", refresh=False), 14 | html.Div(id="content"), 15 | ] 16 | ) 17 | 18 | @app.callback(Output("content", "children"), [Input("link1", "title")]) 19 | def display_title(title): 20 | return title 21 | 22 | dash_dcc.start_server(app) 23 | 24 | title_exists = dash_dcc.find_element("#link1").get_attribute("title") 25 | 26 | assert title_exists == "This is a test title!" 27 | 28 | assert dash_dcc.get_logs() == [] 29 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/misc/test_inline.py: -------------------------------------------------------------------------------- 1 | from dash import Dash, html, dcc 2 | 3 | 4 | def test_inline_props(dash_dcc): 5 | app = Dash(__name__) 6 | 7 | options = ["one", "two", "three"] 8 | app.layout = html.Div( 9 | [ 10 | html.Div( 11 | [ 12 | html.H2(f"Inline: {inline}"), 13 | dcc.RadioItems(options=options, inline=inline), 14 | dcc.Checklist(options=options, inline=inline), 15 | ] 16 | ) 17 | for inline in [True, False] 18 | ] 19 | ) 20 | 21 | dash_dcc.start_server(app) 22 | dash_dcc.percy_snapshot("RadioItems/Checklist-inline") 23 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/sliders/assets/transform.js: -------------------------------------------------------------------------------- 1 | window.dccFunctions = window.dccFunctions || {}; 2 | window.dccFunctions.transformTooltip = function(value) { 3 | return "Transformed " + value 4 | } 5 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/upload/upload-assets/upft001.csv: -------------------------------------------------------------------------------- 1 | city,country 2 | montréal,canada 3 | 京都市,japan 4 | burlington,usa 5 | -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/upload/upload-assets/upft001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/tests/integration/upload/upload-assets/upft001.png -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/upload/upload-assets/upft001.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/tests/integration/upload/upload-assets/upft001.xls -------------------------------------------------------------------------------- /components/dash-core-components/tests/integration/upload/upload-assets/upft001.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-core-components/tests/integration/upload/upload-assets/upft001.xlsx -------------------------------------------------------------------------------- /components/dash-core-components/vignettes/dash-core-components.html.asis: -------------------------------------------------------------------------------- 1 | %\VignetteEngine{knitr::knitr} 2 | %\VignetteIndexEntry{Dash Core Components} 3 | %\usepackage[utf8]{inputenc} 4 | -------------------------------------------------------------------------------- /components/dash-html-components/.builderrc: -------------------------------------------------------------------------------- 1 | --- 2 | archetypes: 3 | - dash-components-archetype 4 | -------------------------------------------------------------------------------- /components/dash-html-components/.eslintignore: -------------------------------------------------------------------------------- 1 | .tox 2 | build/ 3 | dist/ 4 | node_modules/ 5 | .npm 6 | vv/ 7 | venv/ 8 | *.pyc 9 | *.egg-info 10 | *.log 11 | .DS_Store 12 | lib/bundle.js 13 | lib/bundle.js.map 14 | lib/metadata.json 15 | .idea 16 | dash_html_components/ 17 | -------------------------------------------------------------------------------- /components/dash-html-components/.gitignore: -------------------------------------------------------------------------------- 1 | .tox 2 | build/ 3 | dist/ 4 | node_modules/ 5 | .npm 6 | vv/ 7 | venv/ 8 | *.pyc 9 | *.egg-info 10 | *.log 11 | .DS_Store 12 | lib/bundle.js 13 | lib/bundle.js.map 14 | lib/metadata.json 15 | Project.toml 16 | .idea 17 | 18 | /scripts/data/attributes.html 19 | 20 | /src 21 | 22 | /build 23 | /dash_html_components 24 | /deps 25 | /inst 26 | /man 27 | /R 28 | DESCRIPTION 29 | NAMESPACE 30 | -------------------------------------------------------------------------------- /components/dash-html-components/LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: Plotly, Inc. 3 | -------------------------------------------------------------------------------- /components/dash-html-components/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dash_html_components/dash_html_components.min.js 2 | include dash_html_components/dash_html_components.min.js.map 3 | include dash_html_components/metadata.json 4 | include dash_html_components/package-info.json 5 | include LICENSE.md 6 | include README.md 7 | include package.json 8 | -------------------------------------------------------------------------------- /components/dash-html-components/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | module.exports = { presets }; 7 | -------------------------------------------------------------------------------- /components/dash-html-components/scripts/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": {"node": true}, 3 | "rules": { 4 | "no-console": 0, 5 | "import/no-nodejs-modules": 0, 6 | "import/no-commonjs": 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /components/dash-html-components/scripts/extract-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | SCRIPT_DIR=`dirname $0` 5 | 6 | node $SCRIPT_DIR/extract-attributes.js 7 | node $SCRIPT_DIR/extract-elements.js 8 | -------------------------------------------------------------------------------- /components/dash-html-components/scripts/generate-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | SCRIPT_DIR=`dirname $0` 5 | 6 | node $SCRIPT_DIR/generate-components.js $SCRIPT_DIR/data/elements.txt 7 | node $SCRIPT_DIR/generate-index.js 8 | -------------------------------------------------------------------------------- /components/dash-html-components/scripts/generate-index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Generates an export `src/index.js` file from `src/components` directory 5 | */ 6 | 7 | const fs = require('fs'); 8 | const path = require('path') 9 | 10 | const srcPath = '../src'; 11 | const componentPath = './components'; 12 | const indexFileName = 'index.js'; 13 | 14 | const components = fs 15 | .readdirSync(path.join(srcPath, componentPath)) 16 | .filter(component => component.indexOf('.react.js') > -1) 17 | .map(component => component.replace('.react.js', '')); 18 | 19 | let index = components.reduce((indexStr, component) => ( 20 | indexStr + `import ${component} from '${componentPath}/${component}.react';\n` 21 | ), ''); 22 | 23 | index += `\nexport { 24 | ${components.map(c => ` ${c}`).join(',\n')} 25 | };\n`; 26 | 27 | const indexPath = path.join(srcPath, indexFileName); 28 | console.log(`Writing index for ${components.length} components to ${indexPath}.`); 29 | fs.writeFileSync(indexPath, index); 30 | -------------------------------------------------------------------------------- /components/dash-html-components/setup.py: -------------------------------------------------------------------------------- 1 | import io 2 | import json 3 | from setuptools import setup 4 | 5 | with open("package.json") as f: 6 | package = json.load(f) 7 | 8 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 9 | 10 | setup( 11 | name="dash_html_components", 12 | version=package["version"], 13 | author=package["author"], 14 | author_email="chris@plotly.com", 15 | packages=[package_name], 16 | url="https://github.com/plotly/dash-html-components", 17 | include_package_data=True, 18 | license=package["license"], 19 | description=package["description"] if "description" in package else package_name, 20 | long_description=io.open("README.md", encoding="utf-8").read(), 21 | long_description_content_type="text/markdown", 22 | install_requires=[], 23 | ) 24 | -------------------------------------------------------------------------------- /components/dash-html-components/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-html-components/tests/__init__.py -------------------------------------------------------------------------------- /components/dash-html-components/tests/utils.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def assert_clean_console(TestClass): 5 | def assert_no_console_errors(TestClass): 6 | TestClass.assertEqual( 7 | TestClass.driver.execute_script("return window.tests.console.error.length"), 8 | 0, 9 | ) 10 | 11 | def assert_no_console_warnings(TestClass): 12 | TestClass.assertEqual( 13 | TestClass.driver.execute_script("return window.tests.console.warn.length"), 14 | 0, 15 | ) 16 | 17 | assert_no_console_warnings(TestClass) 18 | assert_no_console_errors(TestClass) 19 | -------------------------------------------------------------------------------- /components/dash-html-components/vignettes/dash-html-components.html.asis: -------------------------------------------------------------------------------- 1 | %\VignetteEngine{knitr::knitr} 2 | %\VignetteIndexEntry{Dash HTML Components} 3 | %\usepackage[utf8]{inputenc} 4 | -------------------------------------------------------------------------------- /components/dash-table/.config/webpack/base.preprocessing.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ definitions, variables, ...options } = {}) => ({ 2 | ...options, 3 | definitions: definitions || [], 4 | variables: Object.assign({ 5 | mode: 'lazy' 6 | }, variables || {}) 7 | }); -------------------------------------------------------------------------------- /components/dash-table/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = C901, E203, E231, E266, E501, E731, W503 3 | select = B,C,E,F,W,T4 4 | per-file-ignores = 5 | tests/*: E722, F811 -------------------------------------------------------------------------------- /components/dash-table/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # production 7 | /build 8 | /dash_table 9 | /deps 10 | /inst 11 | /man 12 | /R 13 | /src/*.jl 14 | /src/jl/ 15 | DESCRIPTION 16 | NAMESPACE 17 | Project.toml 18 | 19 | # testing 20 | /coverage 21 | /storybook-static/** 22 | 23 | # misc 24 | .DS_Store 25 | .vscode 26 | .env.local 27 | .env.development.local 28 | .env.test.local 29 | .env.production.local 30 | 31 | npm-debug.log* 32 | yarn-debug.log* 33 | yarn-error.log* 34 | 35 | # virtualenv 36 | vv 37 | venv 38 | 39 | # python 40 | *.pyc 41 | 42 | # builds 43 | dash_table.egg-info 44 | lib 45 | dist 46 | *__pycache__* 47 | __pycache__/ 48 | 49 | *.pyc 50 | -------------------------------------------------------------------------------- /components/dash-table/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-table/.npmignore -------------------------------------------------------------------------------- /components/dash-table/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "singleQuote": true, 4 | "jsxSingleQuote": true, 5 | "arrowParens": "avoid", 6 | "bracketSpacing": false, 7 | "trailingComma": "none" 8 | } -------------------------------------------------------------------------------- /components/dash-table/.storybook/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | ['@babel/env', { 3 | useBuiltIns: 'entry', 4 | corejs: 3 5 | }], 6 | '@babel/preset-react' 7 | ]; 8 | 9 | const plugins = [ 10 | '@babel/plugin-transform-regenerator' 11 | ]; 12 | 13 | module.exports = { presets, plugins }; 14 | -------------------------------------------------------------------------------- /components/dash-table/.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const baseConfig = require('./../.config/webpack/base.js')({ 4 | ts: { 5 | transpileOnly: true 6 | }, 7 | preprocessor: { 8 | variables: { 9 | mode: 'eager' 10 | } 11 | } 12 | }); 13 | 14 | module.exports = { 15 | core: { builder: 'webpack5' }, 16 | stories: ['./../tests/visual/percy-storybook/**/*.percy.tsx'], 17 | webpackFinal: async (config, { configType }) => { 18 | // jerry rig everything 19 | config.resolve.alias.core = path.resolve(__dirname, './../src/core'), 20 | config.resolve.alias['dash-table'] = path.resolve(__dirname, './../src/dash-table') 21 | 22 | config.module = baseConfig.module; 23 | config.stats = { 24 | warnings: true 25 | }; 26 | 27 | return config; 28 | } 29 | }; -------------------------------------------------------------------------------- /components/dash-table/@Types/modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'sheetclip' { 2 | const value: { 3 | prototype: { 4 | parse: (text: string) => string[][]; 5 | stringify: (arr: any[][]) => string; 6 | } 7 | }; 8 | 9 | export default value; 10 | } 11 | 12 | declare module 'fast-isnumeric' { 13 | const value: (value: any) => boolean; 14 | 15 | export default value; 16 | } 17 | 18 | declare class Remarkable { 19 | constructor(options?: any); 20 | render(value: string): any; 21 | } 22 | 23 | declare interface RemarkableCtor { 24 | new(options?: any): Remarkable; 25 | } 26 | 27 | declare module 'remarkable' { 28 | export const Remarkable: RemarkableCtor; 29 | } 30 | -------------------------------------------------------------------------------- /components/dash-table/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dash_table/bundle.js 2 | include dash_table/bundle.js.map 3 | include dash_table/async-*.js 4 | include dash_table/async-*.js.map 5 | include dash_table/metadata.json 6 | include dash_table/package-info.json 7 | include LICENSE 8 | include README.md 9 | include package.json 10 | -------------------------------------------------------------------------------- /components/dash-table/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-table/__init__.py -------------------------------------------------------------------------------- /components/dash-table/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dash-table", 3 | "scripts": { 4 | }, 5 | "env": { 6 | }, 7 | "formation": { 8 | "web": { 9 | "quantity": 1 10 | } 11 | }, 12 | "addons": [ 13 | 14 | ], 15 | "buildpacks": [ 16 | { 17 | "url": "heroku/python" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /components/dash-table/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | '@babel/preset-env', 3 | '@babel/preset-react' 4 | ]; 5 | 6 | const plugins = [ 7 | '@babel/plugin-syntax-dynamic-import' 8 | ]; 9 | 10 | module.exports = { presets, plugins }; 11 | -------------------------------------------------------------------------------- /components/dash-table/cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "allowCompoundWords": true, 3 | "ignorePaths": [ 4 | "**/package.json", 5 | "**/package-lock.json", 6 | "**/packages/**", 7 | "**/node_modules/**", 8 | "**/vscode-extension/**", 9 | "**/.git/**", 10 | ".vscode", 11 | "typings" 12 | ], 13 | "ignoreRegExpList": [ 14 | "'" 15 | ], 16 | "language": "en", 17 | "diagnosticLevel": "Error", 18 | "languageSettings": [ 19 | { "languageId": "*", "dictionaries": ["fonts", "css", "html", "npm", "typescript", "python"]} 20 | ], 21 | "words": [ 22 | "Paginator", 23 | "atto", 24 | "corejs", 25 | "deletable", 26 | "femto", 27 | "giga", 28 | "ints", 29 | "memoizer", 30 | "milli", 31 | "nully", 32 | "peta", 33 | "pico", 34 | "plotly", 35 | "selectable", 36 | "tera", 37 | "tooltips", 38 | "uneditable", 39 | "yocto", 40 | "yotta", 41 | "zepto", 42 | "zetta" 43 | ] 44 | } -------------------------------------------------------------------------------- /components/dash-table/dash_table_base/FormatTemplate.py: -------------------------------------------------------------------------------- 1 | from .Format import Format, Group, Scheme, Sign, Symbol 2 | 3 | 4 | def money(decimals, sign=Sign.default): 5 | return Format( 6 | group=Group.yes, 7 | precision=decimals, 8 | scheme=Scheme.fixed, 9 | sign=sign, 10 | symbol=Symbol.yes, 11 | ) 12 | 13 | 14 | def percentage(decimals, rounded=False): 15 | if not isinstance(rounded, bool): 16 | raise TypeError("expected rounded to be a boolean") 17 | 18 | rounded = Scheme.percentage_rounded if rounded else Scheme.percentage 19 | return Format(scheme=rounded, precision=decimals) 20 | -------------------------------------------------------------------------------- /components/dash-table/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dash-table 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /components/dash-table/demo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | import Logger, {DebugLevel, LogLevel} from 'core/Logger'; 6 | 7 | Logger.setDebugLevel(DebugLevel.DEBUG); 8 | Logger.setLogLevel(LogLevel.NONE); 9 | 10 | ReactDOM.render(, document.getElementById('root')); 11 | -------------------------------------------------------------------------------- /components/dash-table/demo/style.less: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 13px; 3 | } 4 | -------------------------------------------------------------------------------- /components/dash-table/karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = config => { 2 | config.set({ 3 | frameworks: ['mocha', 'webpack'], 4 | 5 | plugins: [ 6 | 'karma-webpack', 7 | 'karma-mocha', 8 | 'karma-chrome-launcher' 9 | ], 10 | preprocessors: { 11 | // add webpack as preprocessor 12 | 'tests/js-unit/**/*.ts': ['webpack'] 13 | }, 14 | files: [ 15 | 'node_modules/babel-polyfill/dist/polyfill.js', 16 | 'node_modules/regenerator-runtime/runtime.js', 17 | 'tests/js-unit/**/*.ts' // *.tsx for React Jsx 18 | ], 19 | reporters: ["progress"], 20 | browsers: ["ChromeHeadless"], 21 | webpack: require('./webpack.test.config') 22 | }); 23 | } -------------------------------------------------------------------------------- /components/dash-table/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | junit_family = xunit1 3 | 4 | testpaths = tests/ 5 | addopts = -rsxX -vv 6 | log_format = %(asctime)s | %(levelname)s | %(name)s:%(lineno)d | %(message)s 7 | log_cli_level = ERROR 8 | -------------------------------------------------------------------------------- /components/dash-table/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | ":onlyNpm", 4 | "schedule:daily" 5 | ], 6 | "enabledManagers": ["npm"], 7 | "groupName": "all dependencies", 8 | "groupSlug": "all", 9 | "lockFileMaintenance": { 10 | "enabled": false 11 | }, 12 | "packageRules": [{ 13 | "packageNames": [ 14 | "react-select", 15 | "@types/react-select" 16 | ], 17 | "allowedVersions": "<2.0.0" 18 | }, { 19 | "packagePatterns": [ 20 | "*" 21 | ], 22 | "depTypeList": [ 23 | "dependencies", 24 | "devDependencies" 25 | ], 26 | "groupName": "all dependencies", 27 | "groupSlug": "all" 28 | }, { 29 | "depTypeList": [ 30 | "peerDependencies", 31 | "engines" 32 | ], 33 | "enabled": false 34 | }], 35 | "rangeStrategy": "bump", 36 | "separateMajorMinor": false 37 | } 38 | -------------------------------------------------------------------------------- /components/dash-table/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import json 3 | 4 | with open("package.json") as f: 5 | package = json.load(f) 6 | 7 | package_name = str(package["name"].replace(" ", "_").replace("-", "_")) 8 | 9 | setup( 10 | name=package_name, 11 | version=package["version"], 12 | author=package["author"], 13 | packages=[package_name], 14 | include_package_data=True, 15 | license=package["license"], 16 | description=package["description"] if "description" in package else package_name, 17 | install_requires=[], 18 | ) 19 | -------------------------------------------------------------------------------- /components/dash-table/src/core/Clipboard.ts: -------------------------------------------------------------------------------- 1 | export default class Clipboard { 2 | /*#if TEST_COPY_PASTE*/ 3 | private static value: string; 4 | /*#endif*/ 5 | 6 | public static set(_ev: any, value: string): void { 7 | /*#if TEST_COPY_PASTE*/ 8 | Clipboard.value = value; 9 | /*#else*/ 10 | _ev.clipboardData.setData('text/plain', value); 11 | _ev.preventDefault(); 12 | /*#endif*/ 13 | } 14 | 15 | public static get(_ev: ClipboardEvent) { 16 | let value; 17 | 18 | /*#if TEST_COPY_PASTE*/ 19 | value = Clipboard.value; 20 | /*#else*/ 21 | value = _ev.clipboardData 22 | ? _ev.clipboardData.getData('text/plain') 23 | : undefined; 24 | /*#endif*/ 25 | 26 | return value; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /components/dash-table/src/core/Logger/DebugLevel.ts: -------------------------------------------------------------------------------- 1 | enum DebugLevel { 2 | DEBUG = 6, 3 | NONE = 7 4 | } 5 | 6 | export default DebugLevel; 7 | -------------------------------------------------------------------------------- /components/dash-table/src/core/Logger/LogLevel.ts: -------------------------------------------------------------------------------- 1 | enum LogLevel { 2 | TRACE = 0, 3 | INFO = 1, 4 | WARNING = 2, 5 | ERROR = 3, 6 | FATAL = 4, 7 | NONE = 5 8 | } 9 | export default LogLevel; 10 | -------------------------------------------------------------------------------- /components/dash-table/src/core/browser/isChrome.ts: -------------------------------------------------------------------------------- 1 | export default /Chrome/.test(navigator.userAgent) && 2 | /Google Inc/.test(navigator.vendor); 3 | -------------------------------------------------------------------------------- /components/dash-table/src/core/browser/scrollbarWidth.ts: -------------------------------------------------------------------------------- 1 | export default (target: HTMLElement): Promise => { 2 | const parent = document.createElement('div'); 3 | parent.style.position = 'absolute'; 4 | parent.style.visibility = 'hidden'; 5 | parent.style.width = '100px'; 6 | parent.style.height = '100px'; 7 | parent.style.overflow = 'scroll'; 8 | 9 | const child = document.createElement('div'); 10 | child.style.width = '100px'; 11 | child.style.height = '100px'; 12 | 13 | parent.appendChild(child); 14 | target.appendChild(parent); 15 | 16 | return new Promise(resolve => { 17 | setTimeout(() => { 18 | const width = child.clientWidth - parent.clientWidth; 19 | 20 | target.removeChild(parent); 21 | resolve(width); 22 | }, 0); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /components/dash-table/src/core/cache/index.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | export type CacheKeyFragment = string | number | boolean; 4 | 5 | export function getCache( 6 | cache: Map, 7 | ...key: TKey 8 | ) { 9 | const cacheKeys = key.slice(0, -1); 10 | 11 | return R.reduce( 12 | (c, fragment) => { 13 | return c.get(fragment) || c.set(fragment, new Map()).get(fragment); 14 | }, 15 | cache, 16 | cacheKeys 17 | ) as Map; 18 | } 19 | -------------------------------------------------------------------------------- /components/dash-table/src/core/cache/memoizer.ts: -------------------------------------------------------------------------------- 1 | import {memoizeOne} from 'core/memoizer'; 2 | import {CacheKeyFragment, getCache} from '.'; 3 | 4 | export default () => { 5 | return any>(fn: TEntryFn) => { 6 | const cache = new Map(); 7 | 8 | function get(...key: TKey): TEntryFn { 9 | const lastKey = key.slice(-1)[0]; 10 | 11 | const nestedCache = getCache(cache, ...key); 12 | 13 | return ( 14 | nestedCache.get(lastKey) || 15 | nestedCache.set(lastKey, memoizeOne(fn)).get(lastKey) 16 | ); 17 | } 18 | 19 | return {get}; 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /components/dash-table/src/core/cache/value.ts: -------------------------------------------------------------------------------- 1 | import {CacheKeyFragment, getCache} from '.'; 2 | 3 | export default () => 4 | (fn: (...a: TKey) => TEntry) => { 5 | const cache = new Map(); 6 | 7 | function get(...key: TKey): TEntry { 8 | const lastKey = key.slice(-1)[0]; 9 | 10 | const nestedCache = getCache(cache, ...key); 11 | 12 | return nestedCache.has(lastKey) 13 | ? nestedCache.get(lastKey) 14 | : nestedCache.set(lastKey, fn(...key)).get(lastKey); 15 | } 16 | 17 | return {get}; 18 | }; 19 | -------------------------------------------------------------------------------- /components/dash-table/src/core/comparer.ts: -------------------------------------------------------------------------------- 1 | export function isEqual(obj1: object, obj2: object) { 2 | return ( 3 | obj1 === obj2 || isEqualArgs(Object.values(obj1), Object.values(obj2)) 4 | ); 5 | } 6 | 7 | export function isEqualArgs(args1: any[] | null, args2: any[]): boolean { 8 | if (!args1) { 9 | return false; 10 | } 11 | 12 | const _args1_ = args1.length; 13 | if (_args1_ !== args2.length) { 14 | return false; 15 | } 16 | 17 | for (let i = 0; i < _args1_; ++i) { 18 | if (args1[i] !== args2[i]) { 19 | return false; 20 | } 21 | } 22 | 23 | return true; 24 | } 25 | -------------------------------------------------------------------------------- /components/dash-table/src/core/debounce.ts: -------------------------------------------------------------------------------- 1 | import {ResultFn} from 'core/generic'; 2 | import Logger from 'core/Logger'; 3 | 4 | export default function ( 5 | fn: ResultFn, 6 | wait: number 7 | ) { 8 | let lastTimestamp = 0; 9 | let handle: any; 10 | 11 | return (...args: TArgs) => { 12 | const now = Date.now(); 13 | const delay = Math.min(now - lastTimestamp, wait); 14 | 15 | if (handle) { 16 | Logger.debug('debounce -- clearTimeout'); 17 | clearTimeout(handle); 18 | } 19 | 20 | handle = setTimeout(() => { 21 | Logger.debug('debounce -- execute!'); 22 | fn(...args); 23 | lastTimestamp = Date.now(); 24 | }, delay); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /components/dash-table/src/core/generic.ts: -------------------------------------------------------------------------------- 1 | export type ResultFn = (...args: TArgs) => TEntry; 2 | -------------------------------------------------------------------------------- /components/dash-table/src/core/math/random.ts: -------------------------------------------------------------------------------- 1 | export default (seed: number | undefined = undefined) => { 2 | const lcg = (a: number) => (a * 48271) % 2147483647; 3 | 4 | let safeSeed = seed !== undefined ? lcg(seed) : lcg(Math.random()); 5 | 6 | return () => (safeSeed = lcg(safeSeed)) / 2147483648; 7 | }; 8 | -------------------------------------------------------------------------------- /components/dash-table/src/core/objPropsToCamel.ts: -------------------------------------------------------------------------------- 1 | import {reduce, toPairs, assoc} from 'ramda'; 2 | import {toCamelCase} from 'dash-table/derived/style/py2jsCssProperties'; 3 | 4 | const objPropsToCamel = (value: any): any => 5 | value !== null && typeof value === 'object' 6 | ? reduce( 7 | (acc, [key, pValue]: [string, any]) => 8 | assoc( 9 | toCamelCase(key.split('_')), 10 | objPropsToCamel(pValue), 11 | acc 12 | ), 13 | {} as any, 14 | toPairs(value) 15 | ) 16 | : Array.isArray(value) 17 | ? value.map(objPropsToCamel, value) 18 | : value; 19 | 20 | export default objPropsToCamel; 21 | -------------------------------------------------------------------------------- /components/dash-table/src/core/sorting/multi.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import Logger from 'core/Logger'; 4 | import {SortBy, ISortBy, SortDirection} from 'core/sorting'; 5 | 6 | export default (sortBy: SortBy, sort: ISortBy): SortBy => { 7 | Logger.trace('multi - update sortBy', sortBy, sort); 8 | 9 | sortBy = R.clone(sortBy); 10 | 11 | if (sort.direction === SortDirection.None) { 12 | const currentIndex = R.findIndex( 13 | s => s.column_id === sort.column_id, 14 | sortBy 15 | ); 16 | 17 | if (currentIndex !== -1) { 18 | sortBy.splice(currentIndex, 1); 19 | } 20 | } else { 21 | const current = R.find(s => s.column_id === sort.column_id, sortBy); 22 | 23 | if (current) { 24 | current.direction = sort.direction; 25 | } else { 26 | sortBy.push(sort); 27 | } 28 | } 29 | 30 | return sortBy; 31 | }; 32 | -------------------------------------------------------------------------------- /components/dash-table/src/core/sorting/single.ts: -------------------------------------------------------------------------------- 1 | import Logger from 'core/Logger'; 2 | import {SortBy, ISortBy, SortDirection} from 'core/sorting'; 3 | 4 | export default (sortBy: SortBy, sort: ISortBy): SortBy => { 5 | Logger.trace('single - update sortBy', sortBy, sort); 6 | 7 | return sort.direction === SortDirection.None ? [] : [sort]; 8 | }; 9 | -------------------------------------------------------------------------------- /components/dash-table/src/core/type/index.ts: -------------------------------------------------------------------------------- 1 | export type OptionalMap = { 2 | [tr in TR]?: M; 3 | }; 4 | export type RequiredPluck = {[r in R]: T[r]}; 5 | export type OptionalPluck = {[r in R]?: T[r]}; 6 | 7 | export type RequiredProp = T[R]; 8 | export type OptionalProp = T[R] | undefined; 9 | 10 | export type PropOf = R; 11 | 12 | export type Merge = Omit> & N; 13 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/LazyLoader.ts: -------------------------------------------------------------------------------- 1 | export default class LazyLoader { 2 | public static get xlsx() { 3 | return import( 4 | /* webpackChunkName: "export", webpackMode: "$${{mode}}" */ 'xlsx' 5 | ); 6 | } 7 | 8 | public static get hljs() { 9 | return Promise.resolve( 10 | (window as any).hljs || 11 | import( 12 | /* webpackChunkName: "highlight", webpackMode: "$${{mode}}" */ '../third-party/highlight.js' 13 | ).then(result => result.default) 14 | ); 15 | } 16 | 17 | public static table() { 18 | return import( 19 | /* webpackChunkName: "table", webpackMode: "$${{mode}}" */ 'dash-table/dash/fragments/DataTable' 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/Cell/props.ts: -------------------------------------------------------------------------------- 1 | import {CSSProperties, MouseEvent} from 'react'; 2 | 3 | interface IAttributes { 4 | [key: string]: string | number | boolean; 5 | } 6 | 7 | export interface ICellProps { 8 | active: boolean; 9 | attributes: IAttributes; 10 | className: string; 11 | onClick: (e: MouseEvent) => void; 12 | onDoubleClick: (e: MouseEvent) => void; 13 | onMouseEnter: (e: MouseEvent) => void; 14 | onMouseLeave: (e: MouseEvent) => void; 15 | onMouseMove: (e: MouseEvent) => void; 16 | style?: CSSProperties; 17 | } 18 | 19 | export type ICellPropsWithDefaults = ICellProps; 20 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/Filter/Advanced.tsx: -------------------------------------------------------------------------------- 1 | import React, {PureComponent} from 'react'; 2 | 3 | import IsolatedInput from 'core/components/IsolatedInput'; 4 | 5 | type SetFilter = (ev: any) => void; 6 | 7 | interface IAdvancedFilterProps { 8 | classes: string[]; 9 | colSpan: number; 10 | setFilter: SetFilter; 11 | value?: string; 12 | } 13 | 14 | export default class AdvancedFilter extends PureComponent { 15 | constructor(props: IAdvancedFilterProps) { 16 | super(props); 17 | } 18 | 19 | private submit = (ev: any) => this.props.setFilter(ev); 20 | 21 | render() { 22 | const {colSpan, value} = this.props; 23 | 24 | return ( 25 | 26 | 31 | 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/Filter/FilterOptions.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {FilterCase, IFilterOptions} from 'dash-table/components/Table/props'; 4 | 5 | interface IFilterCaseButtonProps { 6 | filterOptions: IFilterOptions; 7 | toggleFilterOptions: () => void; 8 | } 9 | 10 | export default ({ 11 | filterOptions, 12 | toggleFilterOptions 13 | }: IFilterCaseButtonProps) => ( 14 | 25 | ); 26 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/PageNavigation/props.ts: -------------------------------------------------------------------------------- 1 | import {IPaginator} from 'dash-table/derived/paginator'; 2 | 3 | export interface IPageNavigationProps { 4 | paginator: IPaginator; 5 | page_current: number; 6 | page_count: number | undefined; 7 | } 8 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/Table/shouldComponentUpdate.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | import {isEqual} from 'core/comparer'; 3 | 4 | const DERIVED_REGEX = /^derived_/; 5 | 6 | export default (props: any, nextProps: any, state: any, nextState: any) => 7 | R.any( 8 | key => !DERIVED_REGEX.test(key) && props[key] !== nextProps[key], 9 | R.keysIn({...props, ...nextProps}) 10 | ) || !isEqual(state, nextState); 11 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/Table/style.ts: -------------------------------------------------------------------------------- 1 | // NOTE: need to pin fontawesome-svg-core to <1.3 and free-*-svg-icons to <6 2 | // or we break IE11 3 | import {library} from '@fortawesome/fontawesome-svg-core'; 4 | import {faEyeSlash, faTrashAlt} from '@fortawesome/free-regular-svg-icons'; 5 | import { 6 | faEraser, 7 | faPencilAlt, 8 | faSort, 9 | faSortDown, 10 | faSortUp 11 | } from '@fortawesome/free-solid-svg-icons'; 12 | import { 13 | faAngleLeft, 14 | faAngleRight, 15 | faAngleDoubleLeft, 16 | faAngleDoubleRight 17 | } from '@fortawesome/free-solid-svg-icons'; 18 | 19 | library.add( 20 | faEraser, 21 | faEyeSlash, 22 | faPencilAlt, 23 | faSort, 24 | faSortDown, 25 | faSortUp, 26 | faTrashAlt, 27 | faAngleLeft, 28 | faAngleRight, 29 | faAngleDoubleLeft, 30 | faAngleDoubleRight 31 | ); 32 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/components/tooltipHelper.ts: -------------------------------------------------------------------------------- 1 | export const getPositionalParent = (el: HTMLElement | null = null) => { 2 | if (!el) { 3 | return; 4 | } 5 | 6 | let positionalParent = el; 7 | while ( 8 | getComputedStyle(positionalParent).position !== 'relative' && 9 | getComputedStyle(positionalParent).position !== 'sticky' 10 | ) { 11 | if (!positionalParent.parentElement) { 12 | break; 13 | } 14 | 15 | positionalParent = positionalParent.parentElement; 16 | } 17 | 18 | return positionalParent; 19 | }; 20 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/cell/isActive.ts: -------------------------------------------------------------------------------- 1 | import {ICellCoordinates} from 'dash-table/components/Table/props'; 2 | 3 | export default ( 4 | activeCell: ICellCoordinates | undefined, 5 | row: number, 6 | column: number 7 | ) => !!activeCell && activeCell.row === row && activeCell.column === column; 8 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/cell/isSelected.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import {SelectedCells} from 'dash-table/components/Table/props'; 4 | 5 | export default (selectedCells: SelectedCells, row: number, column: number) => 6 | R.any(cell => cell.row === row && cell.column === column, selectedCells); 7 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/cell/resolveFlag.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | export default (tableFlag: T, columnFlag: T | null | undefined): T => 4 | R.isNil(columnFlag) ? tableFlag : columnFlag; 5 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/edges/operationOfFilters.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import Environment from 'core/environment'; 4 | import {memoizeOneFactory} from 'core/memoizer'; 5 | 6 | import {IConvertedStyle} from '../style'; 7 | import {EdgesMatrices} from './type'; 8 | import {getFilterOpCellEdges} from '.'; 9 | import {traverse2} from 'core/math/matrixZipMap'; 10 | 11 | export default memoizeOneFactory( 12 | ( 13 | columns: number, 14 | filter_action: boolean, 15 | styles: IConvertedStyle[], 16 | listViewStyle: boolean 17 | ) => { 18 | if (!filter_action || columns === 0) { 19 | return; 20 | } 21 | 22 | const edges = new EdgesMatrices( 23 | 1, 24 | columns, 25 | Environment.defaultEdge, 26 | true, 27 | !listViewStyle 28 | ); 29 | 30 | traverse2(R.range(0, 1), R.range(0, columns), (i, j) => 31 | edges.setEdges(i, j, getFilterOpCellEdges()(styles)) 32 | ); 33 | 34 | return edges; 35 | } 36 | ); 37 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/filter/wrapperStyles.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import {memoizeOneFactory} from 'core/memoizer'; 4 | 5 | import {Columns} from 'dash-table/components/Table/props'; 6 | 7 | import { 8 | IConvertedStyle, 9 | getFilterCellStyle, 10 | getFilterOpCellStyle 11 | } from '../style'; 12 | import {traverseMap2} from 'core/math/matrixZipMap'; 13 | 14 | const getter = (columns: Columns, filterStyles: IConvertedStyle[]) => 15 | R.map(column => getFilterCellStyle(column)(filterStyles), columns); 16 | 17 | const opGetter = ( 18 | rows: number, 19 | columns: number, 20 | columnStyles: IConvertedStyle[] 21 | ) => 22 | traverseMap2(R.range(0, rows), R.range(0, columns), () => 23 | getFilterOpCellStyle()(columnStyles) 24 | ); 25 | 26 | export default memoizeOneFactory(getter); 27 | export const derivedFilterOpStyles = memoizeOneFactory(opGetter); 28 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/columnFlag.ts: -------------------------------------------------------------------------------- 1 | export default ( 2 | i: number, 3 | last: number, 4 | flag?: boolean | boolean[] | 'first' | 'last' 5 | ): boolean => 6 | flag === 'last' 7 | ? i === last 8 | : flag === 'first' 9 | ? i === 0 10 | : typeof flag === 'boolean' 11 | ? flag 12 | : !!flag && flag[i]; 13 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/fixedHeaders.ts: -------------------------------------------------------------------------------- 1 | import {Selection} from 'dash-table/components/Table/props'; 2 | 3 | export default ( 4 | fixedColumns: number, 5 | rowDeletable: boolean, 6 | rowSelectable: Selection 7 | ): number => { 8 | const offset = (rowDeletable ? 1 : 0) + (rowSelectable ? 1 : 0); 9 | 10 | return Math.max(0, fixedColumns - offset); 11 | }; 12 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/headerRows.ts: -------------------------------------------------------------------------------- 1 | import {IColumn} from 'dash-table/components/Table/props'; 2 | 3 | const getColLength = (c: IColumn) => 4 | Array.isArray(c.name) ? c.name.length : 1; 5 | 6 | export default (columns: IColumn[]): number => 7 | Math.max(...columns.map(getColLength)); 8 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/indices.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import {Columns} from 'dash-table/components/Table/props'; 4 | 5 | export default ( 6 | columns: Columns, 7 | labels: any[][], 8 | mergeHeaders: boolean 9 | ): number[][] => { 10 | return R.map(rowLabels => { 11 | if (!mergeHeaders) { 12 | return R.range(0, columns.length); 13 | } else { 14 | const columnIndices = [0]; 15 | let compareIndex = 0; 16 | rowLabels.forEach((label, i) => { 17 | if (label === rowLabels[compareIndex]) { 18 | return; 19 | } 20 | columnIndices.push(i); 21 | compareIndex = i; 22 | }); 23 | 24 | return columnIndices; 25 | } 26 | }, labels); 27 | }; 28 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/labels.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import {Columns} from 'dash-table/components/Table/props'; 4 | 5 | const getColNameAt = (c: any, i: number) => 6 | Array.isArray(c.name) ? c.name[i] : c.name; 7 | 8 | export default (columns: Columns, headerRows: number): any[][] => { 9 | return R.map( 10 | headerRowIndex => 11 | columns.map(c => 12 | R.isNil(c.name) && headerRowIndex === headerRows - 1 13 | ? c.id 14 | : getColNameAt(c, headerRowIndex) 15 | ), 16 | R.range(0, headerRows) 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/labelsAndIndices.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import {memoizeOneFactory} from 'core/memoizer'; 4 | 5 | import getHeaderRows from 'dash-table/derived/header/headerRows'; 6 | import getIndices from 'dash-table/derived/header/indices'; 7 | import getLabels from 'dash-table/derived/header/labels'; 8 | 9 | import {Columns} from 'dash-table/components/Table/props'; 10 | 11 | export default memoizeOneFactory( 12 | ( 13 | columns: Columns, 14 | usedColumns: Columns, 15 | merge_duplicate_headers: boolean 16 | ) => { 17 | const headerRows = getHeaderRows(columns); 18 | 19 | const labels = getLabels(usedColumns, headerRows); 20 | const indices = getIndices( 21 | usedColumns, 22 | labels, 23 | merge_duplicate_headers 24 | ); 25 | 26 | return R.zip(labels, indices); 27 | } 28 | ); 29 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/header/wrapperStyles.ts: -------------------------------------------------------------------------------- 1 | import * as R from 'ramda'; 2 | 3 | import {memoizeOneFactory} from 'core/memoizer'; 4 | 5 | import {Columns} from 'dash-table/components/Table/props'; 6 | 7 | import { 8 | IConvertedStyle, 9 | getHeaderCellStyle, 10 | getHeaderOpCellStyle 11 | } from '../style'; 12 | import {traverseMap2} from 'core/math/matrixZipMap'; 13 | 14 | const getter = ( 15 | columns: Columns, 16 | headerRows: number, 17 | headerStyles: IConvertedStyle[] 18 | ) => 19 | traverseMap2(R.range(0, headerRows), columns, (i, column) => 20 | getHeaderCellStyle(i, column)(headerStyles) 21 | ); 22 | 23 | const opGetter = ( 24 | rows: number, 25 | columns: number, 26 | columnStyles: IConvertedStyle[] 27 | ) => 28 | traverseMap2(R.range(0, rows), R.range(0, columns), i => 29 | getHeaderOpCellStyle(i)(columnStyles) 30 | ); 31 | 32 | export default memoizeOneFactory(getter); 33 | export const derivedHeaderOpStyles = memoizeOneFactory(opGetter); 34 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/selects/columns.ts: -------------------------------------------------------------------------------- 1 | import {Columns} from 'dash-table/components/Table/props'; 2 | import {memoizeOneFactory} from 'core/memoizer'; 3 | 4 | const getter = (visibleColumns: Columns, selectedColumns: string[]): string[] => 5 | visibleColumns 6 | .map(c => c.id) 7 | .filter(c => selectedColumns.indexOf(c) !== -1); 8 | 9 | export default memoizeOneFactory(getter); 10 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/selects/rows.ts: -------------------------------------------------------------------------------- 1 | import {Indices} from 'dash-table/components/Table/props'; 2 | import {memoizeOneFactory} from 'core/memoizer'; 3 | 4 | const getter = (indices: Indices, selectedRows: Indices): Indices => { 5 | const map = new Map(); 6 | 7 | indices.forEach((virtualIndex, index) => { 8 | map.set(virtualIndex, index); 9 | }); 10 | 11 | const mappedSelectedRows: number[] = []; 12 | selectedRows.forEach(rowIndex => { 13 | const virtualIndex = map.get(rowIndex); 14 | 15 | if (virtualIndex !== undefined) { 16 | mappedSelectedRows.push(virtualIndex); 17 | } 18 | }); 19 | 20 | return mappedSelectedRows; 21 | }; 22 | 23 | export default memoizeOneFactory(getter); 24 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/style/props.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConditionalBasicFilter, 3 | ConditionalDataCell, 4 | ConditionalCell, 5 | ConditionalHeader 6 | } from 'dash-table/conditional'; 7 | 8 | import IStyle from './IStyle'; 9 | 10 | export {IStyle}; 11 | 12 | export type Style = Partial; 13 | 14 | export type BasicFilter = Style & {if: ConditionalBasicFilter}; 15 | export type DataCell = Style & {if: ConditionalDataCell}; 16 | export type Cell = Style & {if: ConditionalCell}; 17 | export type Header = Style & {if: ConditionalHeader}; 18 | 19 | export type BasicFilters = BasicFilter[]; 20 | export type DataCells = DataCell[]; 21 | export type Cells = Cell[]; 22 | export type Headers = Header[]; 23 | 24 | export type Table = Style; 25 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/style/py2jsCssProperties.ts: -------------------------------------------------------------------------------- 1 | import cssProperties from './cssProperties'; 2 | 3 | export type StyleProperty = string | number; 4 | 5 | export const toCamelCase = (fragments: string[]) => 6 | fragments 7 | .map((f, i) => (i ? f.charAt(0).toUpperCase() + f.substring(1) : f)) 8 | .join(''); 9 | 10 | const toKebabCase = (fragments: string[]) => fragments.join('-'); 11 | const toSnakeCase = (fragments: string[]) => fragments.join('_'); 12 | 13 | const camels: string[] = []; 14 | const entries: [string, string][] = []; 15 | 16 | cssProperties.forEach(prop => { 17 | const camel = toCamelCase(prop); 18 | 19 | camels.push(camel); 20 | 21 | entries.push([camel, camel]); 22 | entries.push([toKebabCase(prop), camel]); 23 | entries.push([toSnakeCase(prop), camel]); 24 | }); 25 | 26 | export default new Map(entries); 27 | 28 | export const KnownCssProperties = camels; 29 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/derived/table/data_loading.ts: -------------------------------------------------------------------------------- 1 | import {ILoadingState} from 'dash-table/components/Table/props'; 2 | 3 | export default function dataLoading(loading_state: ILoadingState | undefined) { 4 | return loading_state && 5 | loading_state.is_loading && 6 | (loading_state.prop_name === 'data' || 7 | loading_state.prop_name === '' || 8 | loading_state.prop_name === undefined) 9 | ? true 10 | : false; 11 | } 12 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/index.ts: -------------------------------------------------------------------------------- 1 | import 'css.escape'; // polyfill 2 | 3 | import Environment from 'core/environment'; 4 | import Logger from 'core/Logger'; 5 | 6 | import DataTable from 'dash-table/dash/DataTable'; 7 | 8 | Logger.setDebugLevel(Environment.debugLevel); 9 | Logger.setLogLevel(Environment.logLevel); 10 | 11 | export {DataTable}; 12 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/syntax-tree/QuerySyntaxTree.ts: -------------------------------------------------------------------------------- 1 | import SyntaxTree from 'core/syntax-tree'; 2 | 3 | import queryLexicon from './lexicon/query'; 4 | 5 | export default class QuerySyntaxTree extends SyntaxTree { 6 | constructor(query: string) { 7 | super(queryLexicon, query); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/syntax-tree/lexeme/block.ts: -------------------------------------------------------------------------------- 1 | import Logger from 'core/Logger'; 2 | import {LexemeType, IUnboundedLexeme} from 'core/syntax-tree/lexicon'; 3 | 4 | export const blockClose: IUnboundedLexeme = { 5 | nesting: -1, 6 | regexp: /^\)/, 7 | type: LexemeType.BlockClose 8 | }; 9 | 10 | export const blockOpen: IUnboundedLexeme = { 11 | evaluate: (target, tree) => { 12 | Logger.trace('evaluate -> ()', target, tree); 13 | 14 | const t = tree as any; 15 | 16 | return t.block.lexeme.evaluate(target, t.block); 17 | }, 18 | type: LexemeType.BlockOpen, 19 | nesting: 1, 20 | subType: '()', 21 | priority: 1, 22 | regexp: /^\(/, 23 | syntaxer: (lexs: any[]) => { 24 | return Object.assign( 25 | { 26 | block: lexs.slice(1, lexs.length - 1) 27 | }, 28 | lexs[0] 29 | ); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/tooltips/props.ts: -------------------------------------------------------------------------------- 1 | import {ConditionalDataCell} from 'dash-table/conditional'; 2 | 3 | export enum TooltipSyntax { 4 | Text = 'text', 5 | Markdown = 'markdown' 6 | } 7 | 8 | export enum TooltipUsage { 9 | Both = 'both', 10 | Data = 'data', 11 | Header = 'header' 12 | } 13 | 14 | export interface ITooltip { 15 | use_with?: TooltipUsage; 16 | delay?: number | null; 17 | duration?: number | null; 18 | type?: TooltipSyntax; 19 | value: string; 20 | } 21 | 22 | export type Tooltip = string | ITooltip; 23 | export type ConditionalTooltip = ITooltip & {if: ConditionalDataCell}; 24 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/type/any.ts: -------------------------------------------------------------------------------- 1 | import {IAnyColumn} from 'dash-table/components/Table/props'; 2 | 3 | export default (value: any, _options: IAnyColumn) => { 4 | return {success: true, value}; 5 | }; 6 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/type/formatter.ts: -------------------------------------------------------------------------------- 1 | import {ColumnType, IColumnType} from 'dash-table/components/Table/props'; 2 | 3 | import {getFormatter as getNumberFormatter} from './number'; 4 | 5 | const DEFAULT_FORMATTER = (value: any) => value; 6 | export default (c: IColumnType) => { 7 | let formatter; 8 | switch (c.type) { 9 | case ColumnType.Numeric: 10 | formatter = getNumberFormatter(c.format as any); 11 | break; 12 | } 13 | 14 | return formatter || DEFAULT_FORMATTER; 15 | }; 16 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/type/null.ts: -------------------------------------------------------------------------------- 1 | import {ITypeColumn} from 'dash-table/components/Table/props'; 2 | import {IReconciliation} from './reconcile'; 3 | 4 | export const reconcileNull = ( 5 | value: any, 6 | options: ITypeColumn | undefined 7 | ): IReconciliation => { 8 | const allowNull = Boolean( 9 | options && options.validation && options.validation.allow_null 10 | ); 11 | const nully = isNully(value); 12 | 13 | return { 14 | success: nully && allowNull, 15 | value: nully ? null : value 16 | }; 17 | }; 18 | 19 | export const isNully = (value: any) => 20 | value === undefined || 21 | value === null || 22 | (typeof value === 'number' && (isNaN(value) || !isFinite(value))); 23 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/type/text.ts: -------------------------------------------------------------------------------- 1 | import {ITextColumn} from 'dash-table/components/Table/props'; 2 | import {isNully, reconcileNull} from './null'; 3 | import {IReconciliation} from './reconcile'; 4 | 5 | export function coerce( 6 | value: any, 7 | options: ITextColumn | undefined 8 | ): IReconciliation { 9 | return isNully(value) 10 | ? reconcileNull(value, options) 11 | : typeof value === 'string' 12 | ? {success: true, value} 13 | : {success: true, value: JSON.stringify(value)}; 14 | } 15 | 16 | export function validate( 17 | value: any, 18 | options: ITextColumn | undefined 19 | ): IReconciliation { 20 | return typeof value === 'string' 21 | ? {success: true, value} 22 | : reconcileNull(value, options); 23 | } 24 | -------------------------------------------------------------------------------- /components/dash-table/src/dash-table/utils/generate.ts: -------------------------------------------------------------------------------- 1 | export default function genRandomId(prefix: string, radix = 36) { 2 | return prefix + Math.random().toString(radix).substring(2); 3 | } 4 | -------------------------------------------------------------------------------- /components/dash-table/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-table/tests/__init__.py -------------------------------------------------------------------------------- /components/dash-table/tests/js-unit/isEditable_test.ts: -------------------------------------------------------------------------------- 1 | import {expect} from 'chai'; 2 | 3 | import resolveFlag from 'dash-table/derived/cell/resolveFlag'; 4 | 5 | describe('isEditable', () => { 6 | it('returns false if table=false, column=false', () => 7 | expect(resolveFlag(false, false)).to.equal(false)); 8 | 9 | it('returns false if table=false, column=undefined', () => 10 | expect(resolveFlag(false, undefined)).to.equal(false)); 11 | 12 | it('returns true if table=false, column=true', () => 13 | expect(resolveFlag(false, true)).to.equal(true)); 14 | 15 | it('returns false if table=true, column=false', () => 16 | expect(resolveFlag(true, false)).to.equal(false)); 17 | 18 | it('returns true if table=true, column=undefined', () => 19 | expect(resolveFlag(true, undefined)).to.equal(true)); 20 | 21 | it('returns true if table=true, column=true', () => 22 | expect(resolveFlag(true, true)).to.equal(true)); 23 | }); 24 | -------------------------------------------------------------------------------- /components/dash-table/tests/js-unit/loadingState.ts: -------------------------------------------------------------------------------- 1 | import {expect} from 'chai'; 2 | 3 | import dataLoading from 'dash-table/derived/table/data_loading'; 4 | 5 | describe('loading state uneditable', () => { 6 | it('returns true when data are loading', () => { 7 | const loading = dataLoading({ 8 | is_loading: true, 9 | prop_name: 'data', 10 | component_name: '' 11 | }); 12 | 13 | expect(loading).to.equal(true); 14 | }); 15 | 16 | it('returns false when a non-data prop is loading', () => { 17 | const loading = dataLoading({ 18 | is_loading: true, 19 | prop_name: 'style_cell_conditional', 20 | component_name: '' 21 | }); 22 | 23 | expect(loading).to.equal(false); 24 | }); 25 | 26 | it('returns false when table is not loading', () => { 27 | const loading = dataLoading({ 28 | is_loading: false, 29 | prop_name: 'data', 30 | component_name: '' 31 | }); 32 | 33 | expect(loading).to.equal(false); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /components/dash-table/tests/js-unit/reconcile_test.ts: -------------------------------------------------------------------------------- 1 | import {expect} from 'chai'; 2 | 3 | import reconcile from 'dash-table/type/reconcile'; 4 | import { 5 | ColumnType, 6 | ChangeAction, 7 | ChangeFailure 8 | } from 'dash-table/components/Table/props'; 9 | 10 | describe('reconcile', () => { 11 | describe('coerce/validate', () => { 12 | it('applies default ', () => { 13 | const res = reconcile(null, { 14 | type: ColumnType.Numeric, 15 | on_change: { 16 | action: ChangeAction.Coerce, 17 | failure: ChangeFailure.Default 18 | }, 19 | validation: { 20 | default: 0 21 | } 22 | }); 23 | 24 | expect(res.success).to.equal(true); 25 | expect(res.value).to.equal(0); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-table/tests/selenium/assets/logo.png -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/assets/solar.csv: -------------------------------------------------------------------------------- 1 | State,Number of Solar Plants,Installed Capacity (MW),Average MW Per Plant,Generation (GWh) 2 | California,289,4395,15.3,10826 3 | Arizona,48,1078,22.5,2550 4 | Nevada,11,238,21.6,557 5 | New Mexico,33,261,7.9,590 6 | Colorado,20,118,5.9,235 7 | Texas,12,187,15.6,354 8 | North Carolina,148,669,4.5,1162 9 | New York,13,53,4.1,84 10 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_export.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pandas as pd 3 | import pytest 4 | import dash.dash_table as dash_table 5 | import dash 6 | import dash.testing.wait as wait 7 | 8 | 9 | @pytest.mark.parametrize( 10 | "format,reader", [("csv", pd.read_csv), ("xlsx", pd.read_excel)] 11 | ) 12 | def test_tbex001_table_export_csv(test, format, reader): 13 | df = pd.read_csv(os.path.join(os.path.dirname(__file__), "assets/solar.csv")) 14 | app = dash.Dash(__name__) 15 | app.layout = dash_table.DataTable( 16 | id="table", 17 | columns=[{"name": i, "id": i} for i in df.columns], 18 | data=df.to_dict("records"), 19 | export_format=format, 20 | ) 21 | test.start_server(app) 22 | test.wait_for_element(".export", timeout=1).click() 23 | 24 | download = os.path.join(test.download_path, "Data." + format) 25 | wait.until(lambda: os.path.exists(download), timeout=3) 26 | 27 | df_bis = reader(download) 28 | assert df_bis.equals(df) 29 | assert test.get_log_errors() == [] 30 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_markdown_assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/components/dash-table/tests/selenium/test_markdown_assets/logo.png -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_markdown_assets/scripts.js: -------------------------------------------------------------------------------- 1 | window.hljs = { 2 | getLanguage: _ => false, // force auto-highlight 3 | highlightAuto: _ => { 4 | return {value: 'hljs override'}; 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_markdown_html.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash.dash_table import DataTable 3 | 4 | 5 | def get_app(markdown_options): 6 | 7 | app = dash.Dash(__name__) 8 | 9 | props = dict( 10 | id="table", 11 | columns=[dict(name="a", id="a", type="text", presentation="markdown")], 12 | data=[dict(a="

html h1 heading

")], 13 | ) 14 | 15 | if markdown_options is not None: 16 | props["markdown_options"] = markdown_options 17 | 18 | app.layout = DataTable(**props) 19 | 20 | return app 21 | 22 | 23 | def test_tmdh001_html_not_allowed(test): 24 | test.start_server(get_app(None)) 25 | 26 | h1_elements = test.find_elements("h1") 27 | 28 | assert len(h1_elements) == 0 29 | assert test.get_log_errors() == [] 30 | 31 | 32 | def test_tmdh002_html_allowed(test): 33 | test.start_server(get_app(dict(html=True))) 34 | 35 | h1_elements = test.find_elements("h1") 36 | 37 | assert len(h1_elements) == 1 38 | assert test.get_log_errors() == [] 39 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_sizing_b.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from test_sizing import szng003_on_prop_change_impl 4 | 5 | 6 | @pytest.mark.parametrize( 7 | "fixed_columns", 8 | [ 9 | # dict(), 10 | dict(fixed_columns=dict(headers=True)), 11 | dict(fixed_columns=dict(headers=True, data=1)), 12 | ], 13 | ) 14 | @pytest.mark.parametrize( 15 | "fixed_rows", 16 | [ 17 | # dict(), 18 | dict(fixed_rows=dict(headers=True)), 19 | dict(fixed_rows=dict(headers=True, data=1)), 20 | ], 21 | ) 22 | @pytest.mark.parametrize( 23 | "merge_duplicate_headers", 24 | [dict(merge_duplicate_headers=True), dict(merge_duplicate_headers=False)], 25 | ) 26 | @pytest.mark.parametrize( 27 | "callback_props", 28 | [ 29 | dict(merge_duplicate_headers=True), 30 | ], 31 | ) 32 | def test_szng003_b_on_prop_change( 33 | test, fixed_columns, fixed_rows, merge_duplicate_headers, callback_props 34 | ): 35 | szng003_on_prop_change_impl( 36 | test, fixed_columns, fixed_rows, merge_duplicate_headers, callback_props 37 | ) 38 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_sizing_x.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from test_sizing import on_focus 4 | 5 | from utils import ( 6 | basic_modes, 7 | generate_mock_data, 8 | ) 9 | 10 | 11 | @pytest.mark.parametrize("props", basic_modes) 12 | def test_szng004_on_focus(test, props): 13 | on_focus(test, props, generate_mock_data) 14 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_sizing_y.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from test_sizing import on_focus 4 | 5 | from utils import ( 6 | basic_modes, 7 | generate_markdown_mock_data, 8 | ) 9 | 10 | 11 | @pytest.mark.parametrize("props", basic_modes) 12 | def test_szng005_on_focus(test, props): 13 | on_focus(test, props, generate_markdown_mock_data) 14 | -------------------------------------------------------------------------------- /components/dash-table/tests/selenium/test_sizing_z.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from test_sizing import on_focus 4 | 5 | from utils import ( 6 | basic_modes, 7 | generate_mixed_markdown_data, 8 | ) 9 | 10 | 11 | @pytest.mark.parametrize("props", basic_modes) 12 | def test_szng006_on_focus(test, props): 13 | on_focus(test, props, generate_mixed_markdown_data) 14 | -------------------------------------------------------------------------------- /components/dash-table/tests/visual/percy-storybook/@Types/modules.d.ts: -------------------------------------------------------------------------------- 1 | declare let module: any; 2 | 3 | declare module '*.csv' { 4 | const value: any; 5 | 6 | export default value; 7 | } 8 | 9 | declare module '@storybook/react' { 10 | export const storiesOf: any; 11 | export const addDecorator: any; 12 | } 13 | 14 | declare module 'sheetclip' { 15 | const value: any; 16 | export default value; 17 | } 18 | 19 | declare module 'fast-isnumeric' { 20 | const value: (value: any) => boolean; 21 | 22 | export default value; 23 | } 24 | 25 | declare class Remarkable { 26 | constructor(options?: any); 27 | render(value: string): any; 28 | } 29 | 30 | declare interface RemarkableCtor { 31 | new (options?: any): Remarkable; 32 | } 33 | 34 | declare module 'remarkable' { 35 | export const Remarkable: RemarkableCtor; 36 | } 37 | -------------------------------------------------------------------------------- /components/dash-table/tests/visual/percy-storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": "./../../..", 5 | "paths": { 6 | "core/*": ["src/core/*"], 7 | "dash-table/*": ["src/dash-table/*"] 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /components/dash-table/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": false, 6 | "experimentalDecorators": true, 7 | "jsx": "react", 8 | "lib": ["esnext", "dom", "es2018.promise"], 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "noImplicitAny": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "sourceMap": false, 15 | "strict": true, 16 | "strictBindCallApply": true, 17 | "strictNullChecks": true, 18 | "strictPropertyInitialization": true, 19 | "target": "esnext", 20 | "traceResolution": false 21 | } 22 | } -------------------------------------------------------------------------------- /components/dash-table/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "baseUrl": ".", 6 | "paths": { 7 | "core/*": [ 8 | "src/core/*" 9 | ], 10 | "dash-table/*": [ 11 | "src/dash-table/*" 12 | ], 13 | "tests/*": [ 14 | "tests/*" 15 | ] 16 | } 17 | }, 18 | "include": [ 19 | "src/**/*", 20 | "demo/**/*", 21 | "@Types/**/*" 22 | ] 23 | } -------------------------------------------------------------------------------- /components/dash-table/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "baseUrl": ".", 6 | "paths": { 7 | "core/*": [ 8 | "src/core/*" 9 | ], 10 | "dash-table/*": [ 11 | "src/dash-table/*" 12 | ], 13 | "tests/*": [ 14 | "tests/*" 15 | ] 16 | } 17 | }, 18 | "include": [ 19 | "src/**/*", 20 | "demo/**/*", 21 | "tests/**/*", 22 | "@Types/**/*" 23 | ] 24 | } -------------------------------------------------------------------------------- /components/dash-table/webpack.config.js: -------------------------------------------------------------------------------- 1 | let config = require('./.config/webpack/base.js')(); 2 | config.externals['prop-types'] = 'PropTypes'; 3 | 4 | module.exports = config; 5 | -------------------------------------------------------------------------------- /components/dash-table/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | const options = { 2 | preprocessor: { 3 | definitions: ['DEV'] 4 | }, 5 | mode: 'development' 6 | }; 7 | 8 | let config = require('./.config/webpack/base.js')(options); 9 | delete config.plugins; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /components/dash-table/webpack.serve.config.js: -------------------------------------------------------------------------------- 1 | const config = require('./webpack.config'); 2 | 3 | config.entry = {main: './demo/index.js'}; 4 | config.output = {filename: 'output.js'}; 5 | config.mode = 'development'; 6 | config.externals = undefined; // eslint-disable-line 7 | config.devtool = 'inline-source-map'; 8 | module.exports = config; 9 | -------------------------------------------------------------------------------- /components/dash-table/webpack.test.config.js: -------------------------------------------------------------------------------- 1 | const options = { 2 | entry: ['@babel/polyfill'], 3 | ts: { 4 | transpileOnly: true 5 | }, 6 | preprocessor: { 7 | definitions: ['TEST', 'TEST_COPY_PASTE'] 8 | }, 9 | mode: 'development' 10 | }; 11 | 12 | let config = require('./.config/webpack/base.js')(options); 13 | 14 | module.exports = config; -------------------------------------------------------------------------------- /dash/_get_app.py: -------------------------------------------------------------------------------- 1 | from textwrap import dedent 2 | 3 | APP = None 4 | 5 | 6 | def get_app(): 7 | if APP is None: 8 | raise Exception( 9 | dedent( 10 | """ 11 | App object is not yet defined. `app = dash.Dash()` needs to be run 12 | before `dash.get_app()` is called and can only be used within apps that use 13 | the `pages` multi-page app feature: `dash.Dash(use_pages=True)`. 14 | 15 | `dash.get_app()` is used to get around circular import issues when Python files 16 | within the pages/` folder need to reference the `app` object. 17 | """ 18 | ) 19 | ) 20 | return APP 21 | -------------------------------------------------------------------------------- /dash/_obsolete.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=too-few-public-methods 2 | from .exceptions import ObsoleteAttributeException 3 | 4 | 5 | class ObsoleteAttribute: 6 | def __init__(self, message: str, exc=ObsoleteAttributeException): 7 | self.message = message 8 | self.exc = exc 9 | 10 | 11 | class ObsoleteChecker: 12 | _obsolete_attributes = { 13 | "run_server": ObsoleteAttribute("app.run_server has been replaced by app.run"), 14 | "long_callback": ObsoleteAttribute( 15 | "app.long_callback has been removed, use app.callback(..., background=True) instead" 16 | ), 17 | } 18 | 19 | def __getattr__(self, name: str): 20 | if name in self._obsolete_attributes: 21 | err = self._obsolete_attributes[name] 22 | raise err.exc(err.message) 23 | return getattr(self.__dict__, name) 24 | -------------------------------------------------------------------------------- /dash/background_callback/__init__.py: -------------------------------------------------------------------------------- 1 | from .managers.celery_manager import ( # noqa: F401,E402 2 | CeleryManager, 3 | ) 4 | from .managers.diskcache_manager import ( # noqa: F401,E402 5 | DiskcacheManager, 6 | ) 7 | -------------------------------------------------------------------------------- /dash/background_callback/_proxy_set_props.py: -------------------------------------------------------------------------------- 1 | class ProxySetProps(dict): 2 | """ 3 | Defer dictionary item setter to run a custom function on change. 4 | Used by background callback manager to save the `set_props` data. 5 | """ 6 | 7 | def __init__(self, on_change): 8 | super().__init__() 9 | self.on_change = on_change 10 | self._data = {} 11 | 12 | def __setitem__(self, key, value): 13 | self.on_change(key, value) 14 | self._data.setdefault(key, {}) 15 | self._data[key] = {**self._data[key], **value} 16 | 17 | def get(self, key, default=None): 18 | return self._data.get(key, default) 19 | -------------------------------------------------------------------------------- /dash/dash-renderer/.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | lib/ 4 | node_modules/ 5 | .npm 6 | vv/ 7 | venv/ 8 | *.pyc 9 | *.egg-info 10 | *.log 11 | .DS_Store 12 | dist 13 | *egg-info* 14 | 15 | dash_renderer/**/*.js 16 | tests/test_clientside/ 17 | -------------------------------------------------------------------------------- /dash/dash-renderer/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .npm 3 | .git/ 4 | vv/ 5 | venv/ 6 | *.pyc 7 | *.log 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /dash/dash-renderer/@Types/modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'cookie' { 2 | const value: { 3 | parse: (cookie: string) => { 4 | _csrf_token: string 5 | } 6 | }; 7 | 8 | export default value; 9 | } 10 | -------------------------------------------------------------------------------- /dash/dash-renderer/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include package.json 2 | include digest.json 3 | include dash_renderer/*.js 4 | include dash_renderer/*.map 5 | -------------------------------------------------------------------------------- /dash/dash-renderer/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/preset-typescript', 4 | '@babel/preset-env', 5 | '@babel/preset-react' 6 | ], 7 | plugins: [ 8 | '@babel/plugin-proposal-class-properties', 9 | ], 10 | }; 11 | -------------------------------------------------------------------------------- /dash/dash-renderer/config/eslint/eslintrc-node.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "browser": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:import/errors", 9 | "plugin:import/warnings", 10 | "plugin:react/recommended" 11 | ], 12 | "plugins": [ 13 | "import", "react" 14 | ], 15 | "parserOptions": { 16 | "ecmaVersion": "2015", 17 | "sourceType": "module", 18 | "ecmaFeatures": { 19 | "jsx": true, 20 | "experimentalObjectRestSpread": true 21 | } 22 | }, 23 | "rules": { 24 | "import/no-commonjs": 0, 25 | "import/no-nodejs-modules": 0 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dash/dash-renderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dash/dash-renderer/karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = config => { 2 | config.set({ 3 | frameworks: ['mocha', 'webpack'], 4 | 5 | plugins: [ 6 | 'karma-webpack', 7 | 'karma-mocha', 8 | 'karma-chrome-launcher' 9 | ], 10 | preprocessors: { 11 | // add webpack as preprocessor 12 | 'tests/**/*.{js,ts}': ['webpack'] 13 | }, 14 | files: [ 15 | 'node_modules/regenerator-runtime/runtime.js', 16 | 'tests/**/*.{js,ts}' 17 | ], 18 | reporters: ["progress"], 19 | browsers: ["Chrome"], 20 | webpack: require('./webpack.test.config.js')[0], 21 | client: { 22 | mocha: { 23 | timeout: 5000 24 | } 25 | } 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /dash/dash-renderer/renderer-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | file=./build/dash_renderer.min.js 3 | if [ ! -f "$file" ]; then 4 | echo "dash-renderer did not build correctly" 5 | exit 1 6 | fi 7 | -------------------------------------------------------------------------------- /dash/dash-renderer/setup.py: -------------------------------------------------------------------------------- 1 | import json 2 | from setuptools import setup 3 | 4 | with open("package.json") as fp: 5 | package = json.load(fp) 6 | 7 | setup( 8 | name="dash_renderer", 9 | version=package["version"], 10 | author="Chris Parmer", 11 | author_email="chris@plotly.com", 12 | packages=["dash_renderer"], 13 | include_package_data=True, 14 | license="MIT", 15 | description="Front-end component renderer for Dash", 16 | install_requires=[], 17 | ) 18 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/DashRenderer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import AppProvider from './AppProvider.react'; 5 | 6 | import './dashApi'; 7 | 8 | class DashRenderer { 9 | constructor(hooks) { 10 | // render Dash Renderer upon initialising! 11 | const container = document.getElementById('react-entry-point'); 12 | 13 | if (ReactDOM.createRoot) { 14 | const root = ReactDOM.createRoot(container); 15 | root.render(); 16 | } else { 17 | ReactDOM.render(, container); 18 | } 19 | } 20 | } 21 | 22 | export {DashRenderer}; 23 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/actions/constants.js: -------------------------------------------------------------------------------- 1 | const actionList = { 2 | ON_PROP_CHANGE: 1, 3 | SET_REQUEST_QUEUE: 1, 4 | SET_GRAPHS: 1, 5 | SET_PATHS: 1, 6 | SET_LAYOUT: 1, 7 | SET_APP_LIFECYCLE: 1, 8 | SET_CONFIG: 1, 9 | ADD_HTTP_HEADERS: 1, 10 | ON_ERROR: 1, 11 | SET_HOOKS: 1, 12 | INSERT_COMPONENT: 1, 13 | REMOVE_COMPONENT: 1 14 | }; 15 | 16 | export const getAction = action => { 17 | if (actionList[action]) { 18 | return action; 19 | } 20 | throw new Error(`${action} is not defined.`); 21 | }; 22 | 23 | export const MAX_AUTH_RETRIES = 1; 24 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/actions/isLoading.ts: -------------------------------------------------------------------------------- 1 | import {createAction} from 'redux-actions'; 2 | 3 | import {IsLoadingActionType, IsLoadingState} from '../reducers/isLoading'; 4 | 5 | export const setIsLoading = createAction( 6 | IsLoadingActionType.Set 7 | ); 8 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/actions/loading.ts: -------------------------------------------------------------------------------- 1 | import {createAction} from 'redux-actions'; 2 | import {DashLayoutPath} from '../types/component'; 3 | 4 | export type LoadingPayload = { 5 | path: DashLayoutPath; 6 | property: string; 7 | id: any; 8 | }[]; 9 | 10 | export const loading = createAction('LOADING'); 11 | export const loaded = createAction('LOADED'); 12 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/actions/requestDependencies.ts: -------------------------------------------------------------------------------- 1 | import {batch} from 'react-redux'; 2 | import {setGraphs} from './index'; 3 | import apiThunk from './api'; 4 | 5 | export function requestDependencies() { 6 | return (dispatch: any, getState: any) => { 7 | batch(() => { 8 | const {graphs} = getState(); 9 | dispatch(setGraphs({...graphs, reset: true})); 10 | dispatch( 11 | apiThunk('_dash-dependencies', 'GET', 'dependenciesRequest') 12 | ); 13 | }); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/core/Loading.react.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import React from 'react'; 3 | import PropTypes from 'prop-types'; 4 | 5 | function Loading(props) { 6 | if (props.isLoading) { 7 | return
; 8 | } 9 | return null; 10 | } 11 | 12 | Loading.propTypes = { 13 | isLoading: PropTypes.bool.isRequired 14 | }; 15 | 16 | export default connect(state => ({ 17 | isLoading: state.isLoading 18 | }))(Loading); 19 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/core/Toolbar.css: -------------------------------------------------------------------------------- 1 | ._dash-undo-redo { 2 | position: fixed; 3 | bottom: 30px; 4 | left: 30px; 5 | font-size: 20px; 6 | text-align: center; 7 | z-index: 9999; 8 | background-color: rgba(255, 255, 255, 0.9); 9 | } 10 | ._dash-undo-redo > div { 11 | position: relative; 12 | } 13 | ._dash-undo-redo-link { 14 | color: #0074d9; 15 | cursor: pointer; 16 | margin-left: 10px; 17 | margin-right: 10px; 18 | display: inline-block; 19 | opacity: 0.2; 20 | } 21 | ._dash-undo-redo-link:hover { 22 | opacity: 1; 23 | } 24 | ._dash-undo-redo-link ._dash-icon-undo { 25 | font-size: 20px; 26 | transform: rotate(270deg); 27 | } 28 | ._dash-undo-redo-link ._dash-icon-redo { 29 | font-size: 20px; 30 | transform: rotate(90deg); 31 | } 32 | ._dash-undo-redo-link ._dash-undo-redo-label { 33 | font-size: 15px; 34 | } 35 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/GlobalErrorContainerPassthrough.react.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | class GlobalErrorContainer extends Component { 5 | constructor(props) { 6 | super(props); 7 | } 8 | render() { 9 | return
{this.props.children}
; 10 | } 11 | } 12 | 13 | GlobalErrorContainer.propTypes = { 14 | children: PropTypes.object 15 | }; 16 | 17 | export default GlobalErrorContainer; 18 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/Percy.css: -------------------------------------------------------------------------------- 1 | .percy-show { 2 | display: none; 3 | } 4 | 5 | @media only percy { 6 | .percy-hide { 7 | display: none; 8 | } 9 | .percy-show { 10 | display: block; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/BellIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/ClockIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/CollapseIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/DebugIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/Expand.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/LeftArrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/OffIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/ReloadIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/components/error/icons/RightArrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/config.ts: -------------------------------------------------------------------------------- 1 | export type DashConfig = { 2 | url_base_pathname: string; 3 | requests_pathname_prefix: string; 4 | ui: boolean; 5 | props_check: boolean; 6 | show_undo_redo: boolean; 7 | suppress_callback_exceptions: boolean; 8 | update_title: string; 9 | hot_reload?: { 10 | interval: number; 11 | max_retry: number; 12 | }; 13 | validation_layout: any; 14 | children_props: {[k: string]: {[k: string]: string[]}}; 15 | fetch: { 16 | credentials: string; 17 | headers: { 18 | Accept: string; 19 | 'Content-Type': string; 20 | }; 21 | }; 22 | serve_locally?: boolean; 23 | plotlyjs_url?: string; 24 | }; 25 | 26 | export default function getConfigFromDOM(): DashConfig { 27 | const configElement = document.getElementById('_dash-config'); 28 | return JSON.parse( 29 | configElement?.textContent ? configElement?.textContent : '{}' 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/constants/constants.js: -------------------------------------------------------------------------------- 1 | export const REDIRECT_URI_PATHNAME = '/_oauth2/callback'; 2 | export const OAUTH_COOKIE_NAME = 'plotly_oauth_token'; 3 | export const JWT_EXPIRED_MESSAGE = 'JWT Expired'; 4 | 5 | export const STATUS = { 6 | OK: 200, 7 | PREVENT_UPDATE: 204, 8 | // We accept both 400 and 401 for JWT token expiry responses. 9 | // Some servers use code 400 for expired tokens, because 10 | // they reserve 401 for cases that require user action 11 | BAD_REQUEST: 400, 12 | UNAUTHORIZED: 401, 13 | CLIENTSIDE_ERROR: 'CLIENTSIDE_ERROR', 14 | NO_RESPONSE: 'NO_RESPONSE' 15 | }; 16 | 17 | export const STATUSMAP = { 18 | [STATUS.OK]: 'SUCCESS', 19 | [STATUS.PREVENT_UPDATE]: 'NO_UPDATE' 20 | }; 21 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/index.js: -------------------------------------------------------------------------------- 1 | import {DashRenderer} from './DashRenderer'; 2 | import './utils/clientsideFunctions'; 3 | 4 | // make DashRenderer globally available 5 | window.DashRenderer = DashRenderer; 6 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/isSimpleComponent.js: -------------------------------------------------------------------------------- 1 | import {includes, type} from 'ramda'; 2 | 3 | const SIMPLE_COMPONENT_TYPES = ['String', 'Number', 'Null', 'Boolean']; 4 | 5 | export default component => includes(type(component), SIMPLE_COMPONENT_TYPES); 6 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/observers/isLoading.ts: -------------------------------------------------------------------------------- 1 | import {IStoreObserverDefinition} from '../StoreObserver'; 2 | import {IStoreState} from '../store'; 3 | import {getPendingCallbacks} from '../utils/callbacks'; 4 | import {setIsLoading} from '../actions/isLoading'; 5 | 6 | const observer: IStoreObserverDefinition = { 7 | observer: ({dispatch, getState}) => { 8 | const {callbacks, isLoading} = getState(); 9 | 10 | const pendingCallbacks = getPendingCallbacks(callbacks); 11 | 12 | const next = Boolean(pendingCallbacks.length); 13 | 14 | if (isLoading !== next) { 15 | dispatch(setIsLoading(next)); 16 | } 17 | }, 18 | inputs: ['callbacks'] 19 | }; 20 | 21 | export default observer; 22 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/api.js: -------------------------------------------------------------------------------- 1 | import {assoc, assocPath, mergeRight} from 'ramda'; 2 | 3 | export default function createApiReducer(store) { 4 | return function ApiReducer(state = {}, action) { 5 | let newState = state; 6 | if (action.type === store) { 7 | const {id, status, content} = action.payload; 8 | const newRequest = {status, content}; 9 | if (Array.isArray(id)) { 10 | newState = assocPath(id, newRequest, state); 11 | } else if (id) { 12 | newState = assoc(id, newRequest, state); 13 | } else { 14 | newState = mergeRight(state, newRequest); 15 | } 16 | } 17 | return newState; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/appLifecycle.js: -------------------------------------------------------------------------------- 1 | import {getAction} from '../actions/constants'; 2 | import {getAppState} from './constants'; 3 | 4 | function appLifecycle(state = getAppState('STARTED'), action) { 5 | switch (action.type) { 6 | case getAction('SET_APP_LIFECYCLE'): 7 | return getAppState(action.payload); 8 | default: 9 | return state; 10 | } 11 | } 12 | 13 | export default appLifecycle; 14 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/changed.js: -------------------------------------------------------------------------------- 1 | const initialChange = { 2 | id: null, 3 | props: {} 4 | }; 5 | 6 | function changed(state = initialChange) { 7 | // This is empty just to initialize the store. Changes 8 | // are actually recorded in reducer.js so that we can 9 | // resolve paths to id. 10 | return state; 11 | } 12 | 13 | export default changed; 14 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/config.js: -------------------------------------------------------------------------------- 1 | import {getAction} from '../actions/constants'; 2 | import {mergeDeepRight} from 'ramda'; 3 | 4 | export default function config(state = null, action) { 5 | if (action.type === getAction('SET_CONFIG')) { 6 | // Put the components childrenProps in windows for side usage. 7 | window.__dashprivate_childrenProps = mergeDeepRight( 8 | window.__dashprivate_childrenProps || {}, 9 | action.payload.children_props 10 | ); 11 | return action.payload; 12 | } else if (action.type === getAction('ADD_HTTP_HEADERS')) { 13 | return mergeDeepRight(state, { 14 | fetch: { 15 | headers: action.payload 16 | } 17 | }); 18 | } 19 | return state; 20 | } 21 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/constants.js: -------------------------------------------------------------------------------- 1 | export function getAppState(state) { 2 | const stateList = { 3 | STARTED: 'STARTED', 4 | HYDRATED: 'HYDRATED', 5 | DESTROYED: 'DESTROYED' 6 | }; 7 | if (stateList[state]) { 8 | return stateList[state]; 9 | } 10 | throw new Error(`${state} is not a valid app state.`); 11 | } 12 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/dependencyGraph.js: -------------------------------------------------------------------------------- 1 | const initialGraph = {}; 2 | 3 | const graphs = (state = initialGraph, action) => { 4 | if (action.type === 'SET_GRAPHS') { 5 | return action.payload; 6 | } 7 | return state; 8 | }; 9 | 10 | export default graphs; 11 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/hooks.js: -------------------------------------------------------------------------------- 1 | const customHooks = ( 2 | state = { 3 | layout_pre: null, 4 | layout_post: null, 5 | request_pre: null, 6 | request_post: null, 7 | callback_resolved: null, 8 | request_refresh_jwt: null, 9 | bear: false 10 | }, 11 | action 12 | ) => { 13 | switch (action.type) { 14 | case 'SET_HOOKS': 15 | return action.payload; 16 | default: 17 | return state; 18 | } 19 | }; 20 | 21 | export default customHooks; 22 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/isLoading.ts: -------------------------------------------------------------------------------- 1 | export enum IsLoadingActionType { 2 | Set = 'IsLoading.Set' 3 | } 4 | 5 | export interface ILoadingMapAction { 6 | type: IsLoadingActionType.Set; 7 | payload: any; 8 | } 9 | 10 | type IsLoadingState = boolean; 11 | export {IsLoadingState}; 12 | 13 | const DEFAULT_STATE: IsLoadingState = true; 14 | 15 | export default ( 16 | state: IsLoadingState = DEFAULT_STATE, 17 | action: ILoadingMapAction 18 | ) => (action.type === IsLoadingActionType.Set ? action.payload : state); 19 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/reducers/paths.js: -------------------------------------------------------------------------------- 1 | import {getAction} from '../actions/constants'; 2 | 3 | const initialPaths = {strs: {}, objs: {}}; 4 | 5 | const paths = (state = initialPaths, action) => { 6 | if (action.type === getAction('SET_PATHS')) { 7 | return action.payload; 8 | } 9 | return state; 10 | }; 11 | 12 | export default paths; 13 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/registry.js: -------------------------------------------------------------------------------- 1 | export default { 2 | resolve: component => { 3 | const {type, namespace} = component; 4 | 5 | const ns = window[namespace]; 6 | 7 | if (ns) { 8 | if (ns[type]) { 9 | return ns[type]; 10 | } 11 | 12 | throw new Error(`Component ${type} not found in ${namespace}`); 13 | } 14 | 15 | throw new Error(`${namespace} was not found.`); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/types/component.ts: -------------------------------------------------------------------------------- 1 | export type BaseDashProps = { 2 | id?: string; 3 | [key: string]: any; 4 | }; 5 | 6 | export type DashComponent = { 7 | type: string; 8 | namespace: string; 9 | props: BaseDashProps; 10 | }; 11 | 12 | export type UpdatePropsPayload = { 13 | _dash_error?: any; 14 | [key: string]: any; 15 | }; 16 | 17 | export type EnhancedDashProps = 18 | | BaseDashProps 19 | | { 20 | setProps: (props: any) => void; 21 | }; 22 | 23 | // Layout is either a component of a list of components. 24 | export type DashLayout = DashComponent[] | DashComponent; 25 | 26 | export type DashLayoutPath = (string | number)[]; 27 | 28 | export type DashLoadingState = { 29 | is_loading: boolean; 30 | prop_name?: string; 31 | component_name?: string; 32 | }; 33 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/utils/callbacks.ts: -------------------------------------------------------------------------------- 1 | import {omit, values} from 'ramda'; 2 | 3 | import {ICallbacksState} from '../reducers/callbacks'; 4 | import {ICallback} from '../types/callbacks'; 5 | 6 | export const getPendingCallbacks = (state: ICallbacksState) => 7 | Array().concat(...values(omit(['stored', 'completed'], state))); 8 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/utils/stores.ts: -------------------------------------------------------------------------------- 1 | export function getStores() { 2 | const stores = ((window as any).dash_stores = 3 | (window as any).dash_stores || []); 4 | return stores; 5 | } 6 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/utils/wait.ts: -------------------------------------------------------------------------------- 1 | export default async (duration: number) => { 2 | let _resolve: any; 3 | const p = new Promise(resolve => (_resolve = resolve)); 4 | 5 | setTimeout(_resolve, duration); 6 | 7 | return p; 8 | }; 9 | -------------------------------------------------------------------------------- /dash/dash-renderer/src/wrapper/CheckedComponent.tsx: -------------------------------------------------------------------------------- 1 | import checkPropTypes from '../checkPropTypes'; 2 | import {propTypeErrorHandler} from '../exceptions'; 3 | import {validateComponent} from './wrapping'; 4 | 5 | type CheckedComponentProps = { 6 | children: JSX.Element; 7 | element: any; 8 | component: any; 9 | props?: any; 10 | }; 11 | 12 | export default function CheckedComponent(p: CheckedComponentProps) { 13 | const {element, props, children, component} = p; 14 | 15 | validateComponent(component); 16 | 17 | const errorMessage = checkPropTypes( 18 | element.propTypes, 19 | props, 20 | 'component prop', 21 | element 22 | ); 23 | if (errorMessage) { 24 | propTypeErrorHandler(errorMessage, props, component.type); 25 | } 26 | 27 | return children; 28 | } 29 | -------------------------------------------------------------------------------- /dash/dash-renderer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": false, 6 | "experimentalDecorators": true, 7 | "jsx": "react", 8 | "lib": ["esnext", "dom"], 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "noImplicitAny": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "outDir": "./tsbuild", 15 | "sourceMap": false, 16 | "strict": true, 17 | "strictBindCallApply": true, 18 | "strictNullChecks": true, 19 | "strictPropertyInitialization": true, 20 | "target": "esnext", 21 | "traceResolution": false 22 | }, 23 | "include": [ 24 | "src/**/*", 25 | "tests/**/*" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /dash/dash-renderer/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('./webpack.base.config'); 2 | 3 | module.exports = config({}); 4 | -------------------------------------------------------------------------------- /dash/dash-renderer/webpack.test.config.js: -------------------------------------------------------------------------------- 1 | const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); 2 | const config = require('./webpack.base.config'); 3 | 4 | module.exports = config({ 5 | plugins: [ 6 | new NodePolyfillPlugin() 7 | ] 8 | }); -------------------------------------------------------------------------------- /dash/dash_table/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/dash/dash_table/.gitkeep -------------------------------------------------------------------------------- /dash/dcc/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/dash/dcc/.gitkeep -------------------------------------------------------------------------------- /dash/development/__init__.py: -------------------------------------------------------------------------------- 1 | from . import base_component # noqa:F401 2 | -------------------------------------------------------------------------------- /dash/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/dash/favicon.ico -------------------------------------------------------------------------------- /dash/fingerprint.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | cache_regex = re.compile(r"^v[\w-]+m[0-9a-fA-F]+$") 4 | version_clean = re.compile(r"[^\w-]") 5 | 6 | 7 | def build_fingerprint(path, version, hash_value): 8 | path_parts = path.split("/") 9 | filename, extension = path_parts[-1].split(".", 1) 10 | file_path = "/".join(path_parts[:-1] + [filename]) 11 | v_str = re.sub(version_clean, "_", str(version)) 12 | 13 | return f"{file_path}.v{v_str}m{hash_value}.{extension}" 14 | 15 | 16 | def check_fingerprint(path): 17 | path_parts = path.split("/") 18 | name_parts = path_parts[-1].split(".") 19 | 20 | # Check if the resource has a fingerprint 21 | if len(name_parts) > 2 and cache_regex.match(name_parts[1]): 22 | original_name = ".".join([name_parts[0]] + name_parts[2:]) 23 | return "/".join(path_parts[:-1] + [original_name]), True 24 | 25 | return path, False 26 | -------------------------------------------------------------------------------- /dash/html/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/dash/html/.gitkeep -------------------------------------------------------------------------------- /dash/nbextension/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/dash/nbextension/README.md -------------------------------------------------------------------------------- /dash/nbextension/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/dash/nbextension/__init__.py -------------------------------------------------------------------------------- /dash/nbextension/dash.json: -------------------------------------------------------------------------------- 1 | { 2 | "load_extensions": { 3 | "dash/main": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /dash/nbextension/description.yaml: -------------------------------------------------------------------------------- 1 | Type: Jupyter Notebook Extension 2 | Compatibility: 3.x, 4.x, 5.x, 6.x 3 | Name: Jupyter Dash 4 | Main: main.js 5 | Link: README.md 6 | Description: | 7 | Jupyer Dash support 8 | Parameters: 9 | - none 10 | -------------------------------------------------------------------------------- /dash/py.typed: -------------------------------------------------------------------------------- 1 | partial 2 | -------------------------------------------------------------------------------- /dash/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | "group:all" 5 | ], 6 | "pipenv": { 7 | "enabled": true 8 | }, 9 | "pip_requirements": { 10 | "fileMatch": ["requirements.txt", "dev-requirements.txt", "dev-requirements-py37.txt"] 11 | }, 12 | "pip_setup": { 13 | "enabled": true 14 | }, 15 | "packageRules": [{ 16 | "packageNames": [ 17 | "pylint" 18 | ], 19 | "paths": [ 20 | "dev-requirements.txt" 21 | ], 22 | "allowedVersions": "<2.0.0" 23 | }] 24 | } 25 | -------------------------------------------------------------------------------- /dash/testing/__init__.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | 3 | from .._callback_context import context_value as _ctx 4 | from .._utils import AttributeDict as _AD 5 | 6 | 7 | @contextmanager 8 | def ignore_register_page(): 9 | previous = _ctx.get() 10 | copied = _AD(previous) 11 | copied.ignore_register_page = True 12 | _ctx.set(copied) 13 | 14 | try: 15 | yield 16 | finally: 17 | _ctx.set(previous) 18 | -------------------------------------------------------------------------------- /dash/testing/consts.py: -------------------------------------------------------------------------------- 1 | SELENIUM_GRID_DEFAULT = "http://localhost:4444/wd/hub" 2 | -------------------------------------------------------------------------------- /dash/testing/errors.py: -------------------------------------------------------------------------------- 1 | class DashTestingError(Exception): 2 | """Base error for pytest-dash.""" 3 | 4 | 5 | class InvalidDriverError(DashTestingError): 6 | """An invalid selenium driver was specified.""" 7 | 8 | 9 | class NoAppFoundError(DashTestingError): 10 | """No `app` was found in the file.""" 11 | 12 | 13 | class DashAppLoadingError(DashTestingError): 14 | """The dash app failed to load.""" 15 | 16 | 17 | class ServerCloseError(DashTestingError): 18 | """The server cannot be closed.""" 19 | 20 | 21 | class TestingTimeoutError(DashTestingError): 22 | """All timeout error about dash testing.""" 23 | 24 | 25 | class BrowserError(DashTestingError): 26 | """All browser relevant errors.""" 27 | -------------------------------------------------------------------------------- /dash/testing/newhooks.py: -------------------------------------------------------------------------------- 1 | def pytest_setup_options(): 2 | """Called before webdriver is initialized.""" 3 | -------------------------------------------------------------------------------- /dash/types.py: -------------------------------------------------------------------------------- 1 | from typing_extensions import TypedDict, NotRequired 2 | 3 | 4 | class RendererHooks(TypedDict): # pylint: disable=too-many-ancestors 5 | layout_pre: NotRequired[str] 6 | layout_post: NotRequired[str] 7 | request_pre: NotRequired[str] 8 | request_post: NotRequired[str] 9 | callback_resolved: NotRequired[str] 10 | request_refresh_jwt: NotRequired[str] 11 | -------------------------------------------------------------------------------- /dash/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.0.4" 2 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "npm", 3 | "packages": [ 4 | "components/*" 5 | ], 6 | "version": "independent" 7 | } 8 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | junit_family = xunit1 3 | 4 | testpaths = tests/ 5 | addopts = -rsxX -vv 6 | log_format = %(asctime)s | %(levelname)s | %(name)s:%(lineno)d | %(message)s 7 | log_cli_level = ERROR 8 | -------------------------------------------------------------------------------- /requirements/celery.txt: -------------------------------------------------------------------------------- 1 | # Dependencies used by the CeleryLongCallbackManager 2 | redis>=3.5.3,<=5.0.4 3 | kombu<5.4.0 4 | celery[redis]>=5.1.2,<5.4.0 5 | -------------------------------------------------------------------------------- /requirements/ci.txt: -------------------------------------------------------------------------------- 1 | # Dependencies used by CI on github.com/plotly/dash 2 | black==22.3.0 3 | flake8==7.0.0 4 | flaky==3.8.1 5 | flask-talisman==1.0.0 6 | ipython<9.0.0 7 | mimesis<=11.1.0 8 | mock==4.0.3 9 | numpy<=1.26.3 10 | orjson==3.10.3 11 | openpyxl 12 | pandas>=1.4.0 13 | pyarrow 14 | pylint==3.0.3 15 | pytest-mock 16 | pytest-sugar==0.9.6 17 | pyzmq==25.1.2 18 | xlrd>=2.0.1 19 | pytest-rerunfailures 20 | jupyterlab<4.0.0 21 | pyright==1.1.398;python_version>="3.7" 22 | mypy==1.15.0;python_version>="3.12" 23 | -------------------------------------------------------------------------------- /requirements/compress.txt: -------------------------------------------------------------------------------- 1 | flask-compress 2 | -------------------------------------------------------------------------------- /requirements/dev.txt: -------------------------------------------------------------------------------- 1 | # Dependencies used for development new Dash components 2 | coloredlogs>=15.0.1 3 | fire>=0.4.0 4 | PyYAML>=5.4.1 5 | -------------------------------------------------------------------------------- /requirements/diskcache.txt: -------------------------------------------------------------------------------- 1 | # Dependencies used by the DiskcacheLongCallbackManager 2 | diskcache>=5.2.1 3 | multiprocess>=0.70.12 4 | psutil>=5.8.0 5 | -------------------------------------------------------------------------------- /requirements/install.txt: -------------------------------------------------------------------------------- 1 | Flask>=1.0.4,<3.1 2 | Werkzeug<3.1 3 | plotly>=5.0.0 4 | importlib-metadata 5 | typing_extensions>=4.1.1 6 | requests 7 | retrying 8 | nest-asyncio 9 | setuptools 10 | -------------------------------------------------------------------------------- /requirements/testing.txt: -------------------------------------------------------------------------------- 1 | # Dependencies necessary for utilizing Dash provided testing utilities 2 | beautifulsoup4>=4.8.2 3 | cryptography 4 | lxml>=4.6.2 5 | percy>=2.0.2 6 | pytest>=6.0.2 7 | requests[security]>=2.21.0 8 | selenium>=3.141.0,<=4.2.0 9 | waitress>=1.4.4 10 | multiprocess>=0.70.12 11 | psutil>=5.8.0 12 | dash_testing_stub>=0.0.2 13 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/__init__.py -------------------------------------------------------------------------------- /tests/assets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/assets/__init__.py -------------------------------------------------------------------------------- /tests/assets/simple_app.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-docstring 2 | import dash 3 | from dash import html, dcc, Output, Input 4 | from dash.exceptions import PreventUpdate 5 | 6 | 7 | app = dash.Dash(__name__) 8 | 9 | app.layout = html.Div( 10 | [ 11 | dcc.Input(id="value", placeholder="my-value"), 12 | html.Div(["You entered: ", html.Span(id="out")]), 13 | html.Button("style-btn", id="style-btn"), 14 | html.Div("style-container", id="style-output"), 15 | ] 16 | ) 17 | 18 | 19 | @app.callback(Output("out", "children"), Input("value", "value")) 20 | def on_value(value): 21 | if value is None: 22 | raise PreventUpdate 23 | 24 | return value 25 | 26 | 27 | @app.callback(Output("style-output", "style"), [Input("style-btn", "n_clicks")]) 28 | def on_style(value): 29 | if value is None: 30 | raise PreventUpdate 31 | 32 | return {"padding": "10px"} 33 | 34 | 35 | if __name__ == "__main__": 36 | app.run(debug=True, port="10850") 37 | -------------------------------------------------------------------------------- /tests/background_callback/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/background_callback/__init__.py -------------------------------------------------------------------------------- /tests/background_callback/app1.py: -------------------------------------------------------------------------------- 1 | from dash import Dash, Input, Output, dcc, html 2 | import time 3 | 4 | from tests.background_callback.utils import get_background_callback_manager 5 | 6 | background_callback_manager = get_background_callback_manager() 7 | handle = background_callback_manager.handle 8 | 9 | app = Dash(__name__) 10 | app.layout = html.Div( 11 | [ 12 | dcc.Input(id="input", value="initial value"), 13 | html.Div(html.Div([1.5, None, "string", html.Div(id="output-1")])), 14 | ] 15 | ) 16 | 17 | 18 | @app.callback( 19 | Output("output-1", "children"), 20 | [Input("input", "value")], 21 | interval=500, 22 | manager=background_callback_manager, 23 | background=True, 24 | ) 25 | def update_output(value): 26 | time.sleep(0.1) 27 | return value 28 | 29 | 30 | if __name__ == "__main__": 31 | app.run(debug=True) 32 | -------------------------------------------------------------------------------- /tests/background_callback/app2.py: -------------------------------------------------------------------------------- 1 | from dash import Dash, Input, Output, html 2 | 3 | import time 4 | 5 | from tests.background_callback.utils import get_background_callback_manager 6 | 7 | background_callback_manager = get_background_callback_manager() 8 | handle = background_callback_manager.handle 9 | 10 | app = Dash(__name__, background_callback_manager=background_callback_manager) 11 | app.layout = html.Div( 12 | [ 13 | html.Button(id="button-1", children="Click Here", n_clicks=0), 14 | html.Div(id="status", children="Finished"), 15 | html.Div(id="result", children="Not clicked"), 16 | ] 17 | ) 18 | 19 | 20 | @app.callback( 21 | Output("result", "children"), 22 | [Input("button-1", "n_clicks")], 23 | running=[(Output("status", "children"), "Running", "Finished")], 24 | interval=500, 25 | prevent_initial_call=True, 26 | background=True, 27 | ) 28 | def update_output(n_clicks): 29 | time.sleep(2) 30 | return f"Clicked {n_clicks} time(s)" 31 | 32 | 33 | if __name__ == "__main__": 34 | app.run(debug=True) 35 | -------------------------------------------------------------------------------- /tests/background_callback/app_diff_outputs.py: -------------------------------------------------------------------------------- 1 | from dash import Dash, Input, Output, html 2 | 3 | from tests.background_callback.utils import get_background_callback_manager 4 | 5 | background_callback_manager = get_background_callback_manager() 6 | handle = background_callback_manager.handle 7 | 8 | app = Dash(__name__, background_callback_manager=background_callback_manager) 9 | 10 | app.layout = html.Div( 11 | [ 12 | html.Button("click 1", id="button-1"), 13 | html.Button("click 2", id="button-2"), 14 | html.Div(id="output-1"), 15 | html.Div(id="output-2"), 16 | ] 17 | ) 18 | 19 | 20 | def gen_callback(index): 21 | @app.callback( 22 | Output(f"output-{index}", "children"), 23 | Input(f"button-{index}", "n_clicks"), 24 | background=True, 25 | prevent_initial_call=True, 26 | ) 27 | def callback_name(_): 28 | return f"Clicked on {index}" 29 | 30 | 31 | for i in range(1, 3): 32 | gen_callback(i) 33 | 34 | 35 | if __name__ == "__main__": 36 | app.run(debug=True) 37 | -------------------------------------------------------------------------------- /tests/background_callback/app_unordered.py: -------------------------------------------------------------------------------- 1 | from dash import Dash, Input, Output, dcc, State, html, callback 2 | 3 | from tests.background_callback.utils import get_background_callback_manager 4 | 5 | background_callback_manager = get_background_callback_manager() 6 | handle = background_callback_manager.handle 7 | 8 | app = Dash(__name__, background_callback_manager=background_callback_manager) 9 | 10 | app.layout = html.Div( 11 | [ 12 | html.Div(id="output"), 13 | html.Button("click", id="click"), 14 | dcc.Store(data="stored", id="stored"), 15 | ] 16 | ) 17 | 18 | 19 | @callback( 20 | Output("output", "children"), 21 | State("stored", "data"), 22 | Input("click", "n_clicks"), 23 | background=True, 24 | prevent_initial_call=True, 25 | ) 26 | def update_output(stored, n_clicks): 27 | return stored 28 | 29 | 30 | if __name__ == "__main__": 31 | app.run(debug=True) 32 | -------------------------------------------------------------------------------- /tests/background_callback/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | 5 | 6 | if "REDIS_URL" in os.environ: 7 | managers = ["celery", "diskcache"] 8 | else: 9 | print("Skipping celery tests because REDIS_URL is not defined") 10 | managers = ["diskcache"] 11 | 12 | 13 | @pytest.fixture(params=managers) 14 | def manager(request): 15 | return request.param 16 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback009.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | import pytest 5 | 6 | from tests.background_callback.utils import setup_background_callback_app 7 | 8 | 9 | @pytest.mark.skipif( 10 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 11 | ) 12 | def test_lcbc009_short_interval(dash_duo, manager): 13 | with setup_background_callback_app(manager, "app_short_interval") as app: 14 | dash_duo.start_server(app) 15 | dash_duo.find_element("#run-button").click() 16 | dash_duo.wait_for_text_to_equal("#status", "Progress 2/4", 20) 17 | dash_duo.wait_for_text_to_equal("#status", "Finished", 12) 18 | dash_duo.wait_for_text_to_equal("#result", "Clicked '1'") 19 | 20 | time.sleep(2) 21 | # Ensure the progress is still not running 22 | assert dash_duo.find_element("#status").text == "Finished" 23 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback010.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | 5 | from tests.background_callback.utils import setup_background_callback_app 6 | 7 | 8 | @pytest.mark.skipif( 9 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 10 | ) 11 | def test_lcbc010_side_updates(dash_duo, manager): 12 | with setup_background_callback_app(manager, "app_side_update") as app: 13 | dash_duo.start_server(app) 14 | dash_duo.find_element("#run-button").click() 15 | for i in range(1, 4): 16 | dash_duo.wait_for_text_to_equal("#side-status", f"Side Progress {i}/4") 17 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback011.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | 5 | from tests.background_callback.utils import setup_background_callback_app 6 | 7 | 8 | @pytest.mark.skipif( 9 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 10 | ) 11 | def test_lcbc011_long_pattern_matching(dash_duo, manager): 12 | with setup_background_callback_app(manager, "app_pattern_matching") as app: 13 | dash_duo.start_server(app) 14 | for i in range(1, 4): 15 | for _ in range(i): 16 | dash_duo.find_element(f"button:nth-child({i})").click() 17 | 18 | dash_duo.wait_for_text_to_equal("#result", f"Clicked '{i}'") 19 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback012.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | 4 | import pytest 5 | 6 | from tests.background_callback.utils import setup_background_callback_app 7 | 8 | 9 | @pytest.mark.skipif( 10 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 11 | ) 12 | def test_lcbc012_long_callback_ctx(dash_duo, manager): 13 | with setup_background_callback_app(manager, "app_callback_ctx") as app: 14 | dash_duo.start_server(app) 15 | dash_duo.find_element("button:nth-child(1)").click() 16 | dash_duo.wait_for_text_to_equal("#running", "off") 17 | 18 | output = json.loads(dash_duo.find_element("#result").text) 19 | 20 | assert output["triggered"]["index"] == 0 21 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback013.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | 5 | from tests.background_callback.utils import setup_background_callback_app 6 | 7 | 8 | @pytest.mark.skipif( 9 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 10 | ) 11 | def test_lcbc013_unordered_state_input(dash_duo, manager): 12 | with setup_background_callback_app(manager, "app_unordered") as app: 13 | dash_duo.start_server(app) 14 | dash_duo.find_element("#click").click() 15 | 16 | dash_duo.wait_for_text_to_equal("#output", "stored") 17 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback014.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | 5 | from tests.background_callback.utils import setup_background_callback_app 6 | 7 | 8 | @pytest.mark.skipif( 9 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 10 | ) 11 | def test_lcbc014_progress_delete(dash_duo, manager): 12 | with setup_background_callback_app(manager, "app_progress_delete") as app: 13 | dash_duo.start_server(app) 14 | dash_duo.find_element("#start").click() 15 | dash_duo.wait_for_text_to_equal("#output", "done") 16 | 17 | assert dash_duo.find_element("#progress-counter").text == "2" 18 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback015.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | 5 | from tests.background_callback.utils import setup_background_callback_app 6 | 7 | 8 | @pytest.mark.skipif( 9 | sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up" 10 | ) 11 | def test_lcbc015_diff_outputs_same_func(dash_duo, manager): 12 | with setup_background_callback_app(manager, "app_diff_outputs") as app: 13 | dash_duo.start_server(app) 14 | 15 | for i in range(1, 3): 16 | dash_duo.find_element(f"#button-{i}").click() 17 | dash_duo.wait_for_text_to_equal(f"#output-{i}", f"Clicked on {i}") 18 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback017.py: -------------------------------------------------------------------------------- 1 | from tests.background_callback.utils import setup_background_callback_app 2 | 3 | 4 | def test_lcbc017_long_callback_set_props(dash_duo, manager): 5 | with setup_background_callback_app(manager, "app_arbitrary") as app: 6 | dash_duo.start_server(app) 7 | 8 | dash_duo.find_element("#start").click() 9 | 10 | dash_duo.wait_for_text_to_equal("#secondary", "first") 11 | dash_duo.wait_for_style_to_equal( 12 | "#secondary", "background-color", "rgba(255, 0, 0, 1)" 13 | ) 14 | dash_duo.wait_for_text_to_equal("#output", "initial") 15 | dash_duo.wait_for_text_to_equal("#secondary", "second") 16 | dash_duo.wait_for_text_to_equal("#output", "completed") 17 | 18 | dash_duo.find_element("#start-no-output").click() 19 | 20 | dash_duo.wait_for_text_to_equal("#no-output", "started") 21 | dash_duo.wait_for_text_to_equal("#no-output", "completed") 22 | -------------------------------------------------------------------------------- /tests/background_callback/test_basic_long_callback018.py: -------------------------------------------------------------------------------- 1 | from tests.background_callback.utils import setup_background_callback_app 2 | 3 | 4 | def test_lcbc018_background_callback_on_error(dash_duo, manager): 5 | with setup_background_callback_app(manager, "app_bg_on_error") as app: 6 | dash_duo.start_server(app) 7 | 8 | dash_duo.find_element("#start-cb-onerror").click() 9 | 10 | dash_duo.wait_for_contains_text("#cb-output", "callback error") 11 | 12 | dash_duo.find_element("#start-global-onerror").click() 13 | dash_duo.wait_for_contains_text("#global-output", "global error") 14 | -------------------------------------------------------------------------------- /tests/background_callback/test_ctx_cookies.py: -------------------------------------------------------------------------------- 1 | from tests.background_callback.utils import setup_background_callback_app 2 | 3 | 4 | def test_lcbc019_ctx_cookies(dash_duo, manager): 5 | with setup_background_callback_app(manager, "app_ctx_cookies") as app: 6 | dash_duo.start_server(app) 7 | 8 | dash_duo.find_element("#set-cookies").click() 9 | dash_duo.wait_for_contains_text("#intermediate", "ok") 10 | 11 | dash_duo.find_element("#use-cookies").click() 12 | dash_duo.wait_for_contains_text("#output", "cookie-value") 13 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | import dash 5 | from dash._configs import DASH_ENV_VARS 6 | 7 | 8 | @pytest.fixture 9 | def empty_environ(): 10 | for k in DASH_ENV_VARS.keys(): 11 | if k in os.environ: 12 | os.environ.pop(k) 13 | 14 | 15 | @pytest.fixture 16 | def clear_pages_state(): 17 | init_pages_state() 18 | yield 19 | init_pages_state() 20 | 21 | 22 | def init_pages_state(): 23 | """Clear all global state that is used by pages feature.""" 24 | dash._pages.PAGE_REGISTRY.clear() 25 | dash._pages.CONFIG.clear() 26 | dash._pages.CONFIG.__dict__.clear() 27 | -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/__init__.py -------------------------------------------------------------------------------- /tests/integration/callbacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/callbacks/__init__.py -------------------------------------------------------------------------------- /tests/integration/clientside/assets/clientside.mjs: -------------------------------------------------------------------------------- 1 | import {display} from "./clientsideModule.mjs"; 2 | 3 | window.dash_clientside = window.dash_clientside || {}; 4 | window.dash_clientside.clientside_module = Object.assign({}, window.dash_clientside.clientside_module, { 5 | display 6 | }); 7 | -------------------------------------------------------------------------------- /tests/integration/clientside/assets/clientsideModule.mjs: -------------------------------------------------------------------------------- 1 | const display = (value) => 'Client says "' + value + '"'; 2 | 3 | export {display}; 4 | -------------------------------------------------------------------------------- /tests/integration/dash/dash_import_test.py: -------------------------------------------------------------------------------- 1 | # NOTE: this is NOT a pytest test. Just run it as a regular Python script. 2 | # pytest does some magic that makes the issue we're trying to test disappear. 3 | 4 | import types 5 | import os 6 | 7 | import dash 8 | 9 | assert isinstance(dash, types.ModuleType), "dash can be imported" 10 | 11 | this_dir = os.path.dirname(__file__) 12 | with open(os.path.join(this_dir, "../../../dash/version.py")) as fp: 13 | assert dash.__version__ in fp.read(), "version is consistent" 14 | 15 | assert getattr(dash, "Dash").__name__ == "Dash", "access to main Dash class is valid" 16 | -------------------------------------------------------------------------------- /tests/integration/dash/org.py: -------------------------------------------------------------------------------- 1 | # used implicitly by dash_import_test 2 | # to test https://github.com/plotly/dash/issues/1143 3 | import dash_core_components as dcc # noqa: F401 4 | -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/load_first.js: -------------------------------------------------------------------------------- 1 | window.tested = ['load_first']; 2 | var ramdaTest = document.getElementById('ramda-test'); 3 | if (ramdaTest) { 4 | ramdaTest.innerHTML = R.join(' ', R.concat(['hello'], ['world']).map(function(x) { 5 | return _.capitalize(x); 6 | })); 7 | } 8 | -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/load_ignored.js: -------------------------------------------------------------------------------- 1 | window.tested = 'IGNORED'; // Break the chain. -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_css/nested.css: -------------------------------------------------------------------------------- 1 | #content { 2 | padding: 8px; 3 | background-color: purple; 4 | } -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after'); -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after1.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after1'); 2 | -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after10.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after10'); -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after11.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after11'); -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after2.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after2'); -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after3.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after3'); -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_after4.js: -------------------------------------------------------------------------------- 1 | window.tested.push('load_after4'); -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/nested_js/load_last.js: -------------------------------------------------------------------------------- 1 | document.getElementById('tested').innerHTML = JSON.stringify(window.tested); 2 | -------------------------------------------------------------------------------- /tests/integration/dash_assets/assets/reset.css: -------------------------------------------------------------------------------- 1 | body {margin: 0;} 2 | button {height: 18px} 3 | -------------------------------------------------------------------------------- /tests/integration/devtools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/devtools/__init__.py -------------------------------------------------------------------------------- /tests/integration/devtools/hr_assets/hot_reload.css: -------------------------------------------------------------------------------- 1 | #hot-reload-content { 2 | background-color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /tests/integration/devtools/hr_assets/hot_reload.js: -------------------------------------------------------------------------------- 1 | window.cheese = "roquefort"; 2 | -------------------------------------------------------------------------------- /tests/integration/multi_page/assets/app.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/multi_page/assets/app.jpeg -------------------------------------------------------------------------------- /tests/integration/multi_page/assets/birds.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/multi_page/assets/birds.jpeg -------------------------------------------------------------------------------- /tests/integration/multi_page/assets/home.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/multi_page/assets/home.jpeg -------------------------------------------------------------------------------- /tests/integration/multi_page/assets/logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/multi_page/assets/logo.jpeg -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/.no_import.py: -------------------------------------------------------------------------------- 1 | raise Exception("files starting with . should not be imported") 2 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/.no_import/no_import.py: -------------------------------------------------------------------------------- 1 | from dash import register_page 2 | 3 | register_page(__name__) 4 | 5 | raise Exception("files in directories starting with . should not be imported") 6 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/multi_page/pages/__init__.py -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/_no_import.py: -------------------------------------------------------------------------------- 1 | from dash import register_page 2 | 3 | register_page(__name__) 4 | 5 | raise Exception("files starting with _ should not be imported") 6 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/defaults.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html 3 | 4 | 5 | dash.register_page(__name__, id="defaults") 6 | 7 | layout = html.Div("text for defaults", id="text_defaults") 8 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/metas.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html 3 | 4 | dash.register_page( 5 | __name__, 6 | title="Supplied Title", 7 | description="This is the supplied description", 8 | name="Supplied name", 9 | path="/supplied-path", 10 | image="birds.jpeg", 11 | id="metas", 12 | ) 13 | 14 | 15 | def layout(): 16 | return html.Div("text for metas", id="text_metas") 17 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/not_found_404.py: -------------------------------------------------------------------------------- 1 | from dash import html 2 | import dash 3 | 4 | dash.register_page(__name__, path="/404", id="not_found_404") 5 | 6 | 7 | layout = html.Div("text for not_found_404", id="text_not_found_404") 8 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/page1.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html, Input, Output, callback 3 | 4 | 5 | dash.register_page(__name__, id="page1") 6 | 7 | layout = html.Div( 8 | [ 9 | html.Div("text for page1", id="text_page1"), 10 | html.Button("goto page2", id="btn1", n_clicks=0), 11 | ] 12 | ) 13 | 14 | 15 | @callback(Output("url", "pathname"), Input("btn1", "n_clicks")) 16 | def update(n): 17 | if n > 0: 18 | return "/page2" 19 | return dash.no_update 20 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/page2.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html 3 | 4 | 5 | dash.register_page(__name__, id="page2") 6 | 7 | layout = html.Div("text for page2", id="text_page2") 8 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/path_variables.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html 3 | 4 | 5 | dash.register_page(__name__, path_template="/a//b/", id="register_page") 6 | 7 | 8 | def layout(id_a=None, id_b=None, **other_unknown_query_strings): 9 | return html.Div( 10 | [ 11 | html.Div("text for register_page", id="text_register_page"), 12 | html.Div(f"variables from pathname:{id_a} {id_b}", id="path_vars"), 13 | ] 14 | ) 15 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/query_string.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html 3 | 4 | dash.register_page(__name__, id="query_string") 5 | 6 | 7 | def layout(velocity=None, **other_unknown_query_strings): 8 | return html.Div( 9 | [ 10 | html.Div("text for query_string", id="text_query_string"), 11 | dash.dcc.Input(id="velocity", value=velocity), 12 | ] 13 | ) 14 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages/redirect.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import html 3 | 4 | 5 | dash.register_page(__name__, redirect_from=["/old-home-page", "/v2"], id="redirect") 6 | 7 | layout = html.Div("text for redirect", id="text_redirect") 8 | -------------------------------------------------------------------------------- /tests/integration/multi_page/pages_error/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/integration/multi_page/pages_error/__init__.py -------------------------------------------------------------------------------- /tests/integration/multi_page/pages_error/no_layout_page.py: -------------------------------------------------------------------------------- 1 | import dash 2 | 3 | 4 | dash.register_page(__name__) 5 | 6 | # page with no layout 7 | -------------------------------------------------------------------------------- /tests/integration/renderer/initial_state_dash_app_content.html: -------------------------------------------------------------------------------- 1 |
Basic string3.14
Child div with basic string
Grandchild div
Great grandchild
3.14159another basic string
2 | -------------------------------------------------------------------------------- /tests/integration/renderer/test_redraw.py: -------------------------------------------------------------------------------- 1 | import time 2 | from dash import Dash, Input, Output, html 3 | 4 | import dash_test_components as dt 5 | 6 | 7 | def test_rdraw001_redraw(dash_duo): 8 | app = Dash() 9 | 10 | app.layout = html.Div( 11 | [ 12 | html.Div( 13 | dt.DrawCounter(id="counter"), 14 | id="redrawer", 15 | ), 16 | html.Button("redraw", id="redraw"), 17 | ] 18 | ) 19 | 20 | @app.callback( 21 | Output("redrawer", "children"), 22 | Input("redraw", "n_clicks"), 23 | prevent_initial_call=True, 24 | ) 25 | def on_click(_): 26 | return dt.DrawCounter(id="counter") 27 | 28 | dash_duo.start_server(app) 29 | 30 | dash_duo.wait_for_text_to_equal("#counter", "1") 31 | dash_duo.find_element("#redraw").click() 32 | dash_duo.wait_for_text_to_equal("#counter", "2") 33 | time.sleep(1) 34 | dash_duo.wait_for_text_to_equal("#counter", "2") 35 | -------------------------------------------------------------------------------- /tests/integration/security/test_injection.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | from dash import Dash, html, register_page 4 | 5 | injection_script = "" 6 | 7 | 8 | def test_sinj001_url_injection(dash_duo): 9 | app = Dash(__name__, use_pages=True, pages_folder="") 10 | 11 | register_page( 12 | "injected", 13 | layout=html.Div("Regular page"), 14 | title="Title", 15 | description="desc", 16 | name="injected", 17 | path="/injected", 18 | ) 19 | 20 | dash_duo.start_server(app) 21 | 22 | url = f"{dash_duo.server_url}/?'\"-->{injection_script}" 23 | dash_duo.server_url = url 24 | 25 | assert dash_duo.get_logs() == [] 26 | 27 | ret = requests.get(url) 28 | 29 | assert injection_script not in ret.text 30 | -------------------------------------------------------------------------------- /tests/integration/test_pages_redirect_home.py: -------------------------------------------------------------------------------- 1 | import dash 2 | import pytest 3 | 4 | 5 | def test_pare001_redirect_home(dash_duo): 6 | pytest.skip("Revisit later") 7 | 8 | app = dash.Dash(__name__, use_pages=True, pages_folder="") 9 | 10 | dash.register_page( 11 | "multi_layout1", 12 | layout=dash.html.Div("text for multi_layout1", id="text_multi_layout1"), 13 | path="/", 14 | ) 15 | 16 | dash.register_page( 17 | "redirect_home", 18 | redirect_from=["/"], 19 | layout=dash.html.Div("Redirect", id="redirect"), 20 | ) 21 | 22 | app.layout = dash.page_container 23 | 24 | dash_duo.start_server(app) 25 | 26 | dash_duo.wait_for_page(url=f"http://localhost:{dash_duo.server.port}/redirect-home") 27 | dash_duo.wait_for_text_to_equal("#redirect", "Redirect") 28 | 29 | assert dash_duo.get_logs() == [], "browser console should contain no error" 30 | 31 | # clean up after this test, so this redirect does not affect other pages tests 32 | del dash.page_registry["redirect_home"] 33 | -------------------------------------------------------------------------------- /tests/unit/development/TestReactComponentRequired.react.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | // A react component with all of the available proptypes to run tests over 3 | 4 | /** 5 | * This is a description of the component. 6 | * It's multiple lines long. 7 | */ 8 | class ReactComponent extends Component { 9 | render() { 10 | return ""; 11 | } 12 | } 13 | 14 | ReactComponent.propTypes = { 15 | children: React.PropTypes.node, 16 | id: React.PropTypes.string.isRequired, 17 | }; 18 | 19 | export default ReactComponent; 20 | -------------------------------------------------------------------------------- /tests/unit/development/conftest.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from collections import OrderedDict 4 | 5 | import pytest 6 | 7 | from . import _dir 8 | 9 | 10 | @pytest.fixture 11 | def load_test_metadata_json(): 12 | json_path = os.path.join(_dir, "metadata_test.json") 13 | with open(json_path) as data_file: 14 | json_string = data_file.read() 15 | data = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(json_string) 16 | return data 17 | -------------------------------------------------------------------------------- /tests/unit/development/metadata_required_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "This is a description of the component.\nIt's multiple lines long.", 3 | "methods": [], 4 | "props": { 5 | "children": { 6 | "type": { 7 | "name": "node" 8 | }, 9 | "required": false, 10 | "description": "" 11 | }, 12 | "id": { 13 | "type": { 14 | "name": "string" 15 | }, 16 | "required": true, 17 | "description": "" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/unit/library/test_background_callback_validation.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from dash.exceptions import BackgroundCallbackError 4 | from dash.dependencies import Input, Output 5 | from dash._validate import validate_background_callbacks 6 | 7 | 8 | def test_circular_background_callback_progress(): 9 | callback_map = { 10 | "side": { 11 | "output": [Output("side-progress", "children")], 12 | "raw_inputs": [Input("progress", "children")], 13 | }, 14 | "background": { 15 | "output": [Output("result", "children")], 16 | "raw_inputs": [ 17 | Input("click", "n_clicks"), 18 | Input("side-progress", "children"), 19 | ], 20 | "background": {"progress": [Output("progress", "children")]}, 21 | }, 22 | } 23 | 24 | with pytest.raises(BackgroundCallbackError): 25 | 26 | validate_background_callbacks(callback_map) 27 | -------------------------------------------------------------------------------- /tests/unit/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/unit/pages/__init__.py -------------------------------------------------------------------------------- /tests/unit/pages/custom_pages/__init__.py: -------------------------------------------------------------------------------- 1 | # this directory is used for testing custom values of `pages_folder` param that 2 | # need to exist as actual paths. 3 | -------------------------------------------------------------------------------- /tests/unit/pages/custom_pages/page.py: -------------------------------------------------------------------------------- 1 | import dash 2 | 3 | dash.register_page(__name__) 4 | 5 | layout = dash.html.Div("") 6 | -------------------------------------------------------------------------------- /tests/unit/pages/sub_dir/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plotly/dash/910a3cb884a2f769426efee2caad0b97e50e0c72/tests/unit/pages/sub_dir/__init__.py -------------------------------------------------------------------------------- /tests/unit/pages/sub_dir/custom_pages/__init__.py: -------------------------------------------------------------------------------- 1 | # this directory is used for testing custom values of `pages_folder` param that 2 | # need to exist as actual paths. 3 | -------------------------------------------------------------------------------- /tests/unit/pages/sub_dir/custom_pages/page.py: -------------------------------------------------------------------------------- 1 | import dash 2 | 3 | dash.register_page(__name__) 4 | 5 | layout = dash.html.Div("") 6 | -------------------------------------------------------------------------------- /tests/unit/test_testing.py: -------------------------------------------------------------------------------- 1 | from dash.testing import ignore_register_page 2 | from dash import register_page 3 | 4 | 5 | def test_tst001_ignore_register_page(): 6 | with ignore_register_page(): 7 | register_page("/") 8 | --------------------------------------------------------------------------------