diff --git a/.circleci/config.yml b/.circleci/config.yml index 13a4039..70e3312 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,7 +28,7 @@ jobs: - run: name: 🔎 Unit tests command: | - julia -e 'using Pkg; Pkg.update(); Pkg.add(PackageSpec(url="https://github.com/plotly/Dash.jl.git", rev=ENV["CIRCLE_BRANCH"])); Pkg.add(PackageSpec(url="https://github.com/waralex/dash-html-components.git", rev="jl_generator_test")); Pkg.add(PackageSpec(url="https://github.com/waralex/dash-core-components.git", rev="jl_generator_test")); Pkg.build("Dash"); Pkg.build("DashHtmlComponents"); Pkg.build("DashCoreComponents"); Pkg.test("Dash", coverage=true); function precompile_pkgs(); for pkg in collect(keys(Pkg.installed())); if !isdefined(Symbol(pkg), :Symbol) && pkg != "Compat.jl"; @info("Importing $(pkg)..."); try (@eval import $(Symbol(pkg))) catch end; end; end; end; precompile_pkgs()' + julia -e 'using Pkg; Pkg.update(); Pkg.add(PackageSpec(url="https://github.com/waralex/DashBase.jl.git")); Pkg.add(PackageSpec(url="https://github.com/waralex/dash-html-components.git", rev="jl_reverse_test")); Pkg.add(PackageSpec(url="https://github.com/waralex/dash-core-components.git", rev="jl_reverse_test"));Pkg.add(PackageSpec(url="https://github.com/waralex/dash-table.git", rev="jl_reverse_test")); Pkg.add(PackageSpec(url="https://github.com/plotly/Dash.jl.git", rev=ENV["CIRCLE_BRANCH"])); Pkg.build("Dash");Pkg.test("Dash", coverage=true); function precompile_pkgs(); for pkg in collect(keys(Pkg.installed())); if !isdefined(Symbol(pkg), :Symbol) && pkg != "Compat.jl"; @info("Importing $(pkg)..."); try (@eval import $(Symbol(pkg))) catch end; end; end; end; precompile_pkgs()' - run: name: ⚙️ Integration tests diff --git a/Project.toml b/Project.toml index f4814d4..e4ae00d 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,10 @@ version = "0.1.0" [deps] CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" +DashBase = "03207cf0-e2b3-4b91-9ca8-690cf0fb507e" +DashCoreComponents = "1b08a953-4be3-4667-9a23-03c9473d1193" +DashHtmlComponents = "1b08a953-4be3-4667-9a23-341813c6f7a5" +DashTable = "1b08a953-4be3-4667-9a23-d3c7dd0aada8" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" diff --git a/src/Components.jl b/src/Components.jl index cca15f2..2946c99 100644 --- a/src/Components.jl +++ b/src/Components.jl @@ -1,40 +1,3 @@ -module Components -import JSON2 -export Component, <|, hasproperty, is_prop_available, validate - -abstract type AbstractComponent end - - -struct Component <: AbstractComponent - type ::String - namespace ::String - props ::Dict{Symbol, Any} - available_props ::Set{Symbol} - wildcard_props ::Set{Symbol} -end - -JSON2.@format Component begin - available_props => (exclude = true,) - wildcard_props => (exclude = true,) -end - -function <|(comp::Component, value::Any) - comp.props["children"] = value - return comp -end - -hasproperty(c::Component, prop::Symbol) = haskey(c.props, prop) -function is_prop_available(c::Component, prop::Symbol) - if length(c.wildcard_props) > 0 - wild_regs = Regex("^(?$(join(c.wildcard_props, "|")))") - if !isnothing(match(wild_regs, string(prop))) - return true - end - end - - return prop in c.available_props -end - function _validate_children(children::Union{Vector, Tuple}, ids::Set{Symbol}) for child in children @@ -48,17 +11,15 @@ function _validate_children(children, ids::Set{Symbol}) end function _validate(comp::Component, ids::Set{Symbol}) - if haskey(comp.props, :id) - id = Symbol(comp.props[:id]) + if hasproperty(comp, :id) && !isnothing(comp.id) + id = Symbol(comp.id) id in ids && error("Duplicate component id found in the initial layout: $(id)") push!(ids, id) end - _validate_children(get(comp.props, :children, nothing), ids) + hasproperty(comp, :children) && _validate_children(comp.children, ids) end function _validate(non_comp, ids::Set{Symbol}) end function validate(comp::Component) _validate(comp, Set{Symbol}()) end - -end diff --git a/src/Dash.jl b/src/Dash.jl index 9fe3fbb..8f93842 100644 --- a/src/Dash.jl +++ b/src/Dash.jl @@ -1,17 +1,18 @@ module Dash import HTTP, JSON2, CodecZlib, MD5 using Sockets -using MacroTools +using DashBase const ROOT_PATH = realpath(joinpath(@__DIR__, "..")) +const RESOURCE_PATH = realpath(joinpath(ROOT_PATH, "resources")) + include("Components.jl") include("Front.jl") -import .Front -using .Components export dash, Component, Front, callback!, enable_dev_tools!, ClientsideFunction, run_server, PreventUpdate, no_update, @var_str, -Input, Output, State, make_handler +Input, Output, State, make_handler, +DashBase @@ -19,7 +20,6 @@ Input, Output, State, make_handler include("env.jl") include("utils.jl") include("app.jl") -include("resources/registry.jl") include("resources/application.jl") include("handlers.jl") @@ -163,4 +163,73 @@ end get_inetaddr(host::String, port::Integer) = Sockets.InetAddr(parse(IPAddr, host), port) get_inetaddr(host::IPAddr, port::Integer) = Sockets.InetAddr(host, port) + +function __init__() + DashBase.main_registry().dash_dependency = ( + dev = ResourcePkg( + "dash_renderer", + RESOURCE_PATH, version = "1.2.2", + [ + Resource( + relative_package_path = "react@16.8.6/umd/react.production.min.js", + external_url = "https://unpkg.com/react@16.8.6/umd/react.production.min.js", + ), + Resource( + relative_package_path = "react-dom@16.8.6/dist/react-dom.production.min.js", + external_url = "https://unpkg.com/browse/react-dom@16.8.6/umd/react-dom.production.min.js" + ), + Resource( + relative_package_path = "polyfill@7.7.0/dist/polyfill.min.js", + external_url = "https://unpkg.com/@babel/polyfill@7.7.0/dist/polyfill.min.js" + ), + Resource( + relative_package_path = "prop-types@15.7.2/prop-types/prop-types.js", + external_url = "https://unpkg.com/prop-types@15.7.2/prop-types.js", + ), + ] + ), + prod = ResourcePkg( + "dash_renderer", + RESOURCE_PATH, version = "1.2.2", + [ + Resource( + relative_package_path = "react@16.8.6/umd/react.production.min.js", + external_url = "https://unpkg.com/react@16.8.6/umd/react.production.min.js", + ), + Resource( + relative_package_path = "react-dom@16.8.6/dist/react-dom.production.min.js", + external_url = "https://unpkg.com/react-dom@16.8.6/umd/react-dom.production.min.js" + ), + Resource( + relative_package_path = "polyfill@7.7.0/dist/polyfill.min.js", + external_url = "https://unpkg.com/@babel/polyfill@7.7.0/dist/polyfill.min.js" + ), + Resource( + relative_package_path = "prop-types@15.7.2/prop-types/prop-types.min.js", + external_url = "https://unpkg.com/prop-types@15.7.2/prop-types.min.js", + ), + ] + ) + ) + + DashBase.main_registry().dash_renderer = ResourcePkg( + "dash_renderer", + RESOURCE_PATH, version = "1.2.2", + [ + Resource( + relative_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.min.js", + dev_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.dev.js", + external_url = "https://unpkg.com/dash-renderer@1.2.2/dash_renderer/dash_renderer.min.js" + ), + Resource( + relative_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.min.js.map", + dev_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.dev.js.map", + dynamic = true, + ), + ] + ) + + +end + end # module diff --git a/src/Front.jl b/src/Front.jl index e7bc4c0..8f518ef 100644 --- a/src/Front.jl +++ b/src/Front.jl @@ -1,17 +1,4 @@ -module Front import JSON, JSON2, PlotlyBase - -to_dash(t::Any) = t -from_dash(::Type{Any}, t::Any) = t - - -function from_dash(::Type{PlotlyBase.Plot}, t) - data = PlotlyBase.GenericTrace[PlotlyBase.GenericTrace(tr) for tr in t.data] - layout = PlotlyBase.Layout(t.layout) - PlotlyBase.Plot(data, layout) -end - #FIXME It's not elegant, but I didn't find elegant soluiton JSON2.write(io::IO, p::PlotlyBase.Plot; kwargs...) = write(io, JSON.json(p)) -end diff --git a/src/handler/handlers.jl b/src/handler/handlers.jl index 8f18527..9112aa0 100644 --- a/src/handler/handlers.jl +++ b/src/handler/handlers.jl @@ -59,7 +59,7 @@ function _process_callback(app::DashApp, body::String) return Dict( :response => Dict( :props => Dict( - Symbol(app.callbacks[output].dependencies.output[1].property) => Front.to_dash(res) + Symbol(app.callbacks[output].dependencies.output[1].property) => DashBase.to_dash(res) ) ) ) @@ -72,7 +72,7 @@ function _process_callback(app::DashApp, body::String) if !(res[ind] isa NoUpdate) push!(response, Symbol(out.id) => Dict( - Symbol(out.property) => Front.to_dash(res[ind]) + Symbol(out.property) => DashBase.to_dash(res[ind]) ) ) end diff --git a/src/resources/registry.jl b/src/resources/registry.jl deleted file mode 100644 index cd35bd9..0000000 --- a/src/resources/registry.jl +++ /dev/null @@ -1,134 +0,0 @@ -struct Resource - relative_package_path::Union{Nothing, Vector{String}} - dev_package_path::Union{Nothing, Vector{String}} - external_url::Union{Nothing, Vector{String}} - type::Symbol - async::Symbol # :none, :eager, :lazy May be we should use enum - function Resource(;relative_package_path, dev_package_path = nothing, external_url = nothing, type = :js, dynamic = nothing, async=nothing) - (!isnothing(dynamic) && !isnothing(async)) && throw(ArgumentError("Can't have both 'dynamic' and 'async'")) - !in(type, [:js, :css]) && throw(ArgumentError("type must be `:js` or `:css`")) - async_symbol = :none - if !isnothing(dynamic) - dynamic == true && (async_symbol = :lazy) - elseif !isnothing(async) && async != :false - async_symbol = async == :lazy ? :lazy : :eager - end - return new(_path_to_vector(relative_package_path), _path_to_vector(dev_package_path), _path_to_vector(external_url), type, async_symbol) - end -end - -_path_to_vector(s::Nothing) = nothing -_path_to_vector(s::String) = [s] -_path_to_vector(s::Vector{String}) = s - -has_relative_path(r::Resource) = !isnothing(r.relative_package_path) -has_dev_path(r::Resource) = !isnothing(r.dev_package_path) -has_external_url(r::Resource) = !isnothing(r.external_url) - -get_type(r::Resource) = r.type -get_external_url(r::Resource) = r.external_url -get_dev_path(r::Resource) = r.dev_package_path -get_relative_path(r::Resource) = r.relative_package_path - -isdynamic(resource::Resource, eager_loading::Bool) = resource.async == :lazy || (resource.async == :eager && !eager_loading) - -struct ResourcePkg - namespace ::String - path ::String - resources ::Vector{Resource} - version ::String - ResourcePkg(namespace, path, resources = Resource[]; version = "") = new(namespace, path, resources, version) -end - - - -struct ResourcesRegistry - dash_dependency ::NamedTuple{(:dev, :prod), Tuple{ResourcePkg,ResourcePkg}} - dash_renderer ::ResourcePkg - components ::Dict{String, ResourcePkg} - ResourcesRegistry(;dash_dependency, dash_renderer) = new(dash_dependency, dash_renderer, Dict{String, ResourcePkg}()) -end - -function register_package!(registry::ResourcesRegistry, pkg::ResourcePkg) - registry.components[pkg.namespace] = pkg -end - -get_dash_dependencies(registry::ResourcesRegistry, prop_check::Bool) = prop_check ? - registry.dash_dependency[:dev] : - registry.dash_dependency[:prod] - -get_componens_pkgs(registry::ResourcesRegistry) = values(registry.components) -get_dash_renderer_pkg(registry::ResourcesRegistry) = registry.dash_renderer - - - -const RESOURCE_PATH = realpath(joinpath(ROOT_PATH, "resources")) - -const resources_registry = ResourcesRegistry( - dash_dependency = ( - dev = ResourcePkg( - "dash_renderer", - RESOURCE_PATH, version = "1.2.2", - [ - Resource( - relative_package_path = "react@16.8.6/umd/react.production.min.js", - external_url = "https://unpkg.com/react@16.8.6/umd/react.production.min.js", - ), - Resource( - relative_package_path = "react-dom@16.8.6/dist/react-dom.production.min.js", - external_url = "https://unpkg.com/browse/react-dom@16.8.6/umd/react-dom.production.min.js" - ), - Resource( - relative_package_path = "polyfill@7.7.0/dist/polyfill.min.js", - external_url = "https://unpkg.com/@babel/polyfill@7.7.0/dist/polyfill.min.js" - ), - Resource( - relative_package_path = "prop-types@15.7.2/prop-types/prop-types.js", - external_url = "https://unpkg.com/prop-types@15.7.2/prop-types.js", - ), - ] - ), - prod = ResourcePkg( - "dash_renderer", - RESOURCE_PATH, version = "1.2.2", - [ - Resource( - relative_package_path = "react@16.8.6/umd/react.production.min.js", - external_url = "https://unpkg.com/react@16.8.6/umd/react.production.min.js", - ), - Resource( - relative_package_path = "react-dom@16.8.6/dist/react-dom.production.min.js", - external_url = "https://unpkg.com/react-dom@16.8.6/umd/react-dom.production.min.js" - ), - Resource( - relative_package_path = "polyfill@7.7.0/dist/polyfill.min.js", - external_url = "https://unpkg.com/@babel/polyfill@7.7.0/dist/polyfill.min.js" - ), - Resource( - relative_package_path = "prop-types@15.7.2/prop-types/prop-types.min.js", - external_url = "https://unpkg.com/prop-types@15.7.2/prop-types.min.js", - ), - ] - ) - ), - dash_renderer = ResourcePkg( - "dash_renderer", - RESOURCE_PATH, version = "1.2.2", - [ - Resource( - relative_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.min.js", - dev_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.dev.js", - external_url = "https://unpkg.com/dash-renderer@1.2.2/dash_renderer/dash_renderer.min.js" - ), - Resource( - relative_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.min.js.map", - dev_package_path = "dash-renderer@1.2.2/dash-renderer/dash_renderer.dev.js.map", - dynamic = true, - ), - ] - ) -) - -register_package(pkg::ResourcePkg) = register_package!(resources_registry, pkg) - -main_registry() = resources_registry diff --git a/test/Project.toml b/test/Project.toml deleted file mode 100644 index 50fc396..0000000 --- a/test/Project.toml +++ /dev/null @@ -1,13 +0,0 @@ -[deps] -CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" -DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" -Inflate = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" -JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3" -MD5 = "6ac74813-4b46-53a4-afec-0b5dc9d7885c" -LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -SnoopCompile = "aa65fe97-06da-5843-b5b1-d5d13cad87d2" diff --git a/test/TestComponents.jl b/test/TestComponents.jl index 4716506..01310b7 100644 --- a/test/TestComponents.jl +++ b/test/TestComponents.jl @@ -1,169 +1,75 @@ module TestComponents -using Dash +using DashBase export html_div, html_a, dcc_input, dcc_graph, html_h1, html_img function html_div(; kwargs...) - available_props = Set(Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state]) - wild_props = Set(Symbol[Symbol("data-"), Symbol("aria-")]) - wild_regs = r"^(?data-|aria-)" + available_props = Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state] + wild_props = Symbol[Symbol("data-"), Symbol("aria-")] - result = Component("Div", "dash_html_components", Dict{Symbol, Any}(), available_props, Set(Symbol[Symbol("data-"), Symbol("aria-")])) + return Component("html_div", "Div", "dash_html_components", available_props, wild_props; kwargs...) - for (prop, value) = pairs(kwargs) - m = match(wild_regs, string(prop)) - if (length(wild_props) == 0 || isnothing(m)) && !(prop in available_props) - throw(ArgumentError("Invalid property $(string(prop)) for component " * "html_div")) - end - - push!(result.props, prop => Front.to_dash(value)) - end - -return result end -function html_div(children::Any; kwargs...) -result = html_div(;kwargs...) -push!(result.props, :children => Front.to_dash(children)) -return result -end +html_div(children::Any; kwargs...) = html_div(;kwargs..., children = children) html_div(children_maker::Function; kwargs...) = html_div(children_maker(); kwargs...) function html_h1(; kwargs...) - available_props = Set(Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state]) - wild_props = Set(Symbol[Symbol("data-"), Symbol("aria-")]) - wild_regs = r"^(?data-|aria-)" + available_props = Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state] + wild_props = Symbol[Symbol("data-"), Symbol("aria-")] - result = Component("H1", "dash_html_components", Dict{Symbol, Any}(), available_props, Set(Symbol[Symbol("data-"), Symbol("aria-")])) + return Component("html_h1", "H1", "dash_html_components", available_props, wild_props; kwargs...) - for (prop, value) = pairs(kwargs) - m = match(wild_regs, string(prop)) - if (length(wild_props) == 0 || isnothing(m)) && !(prop in available_props) - throw(ArgumentError("Invalid property $(string(prop)) for component " * "html_h1")) - end - - push!(result.props, prop => Front.to_dash(value)) - end - -return result end -function html_h1(children::Any; kwargs...) -result = html_h1(;kwargs...) -push!(result.props, :children => Front.to_dash(children)) -return result -end +html_h1(children::Any; kwargs...) = html_h1(;kwargs..., children = children) html_h1(children_maker::Function; kwargs...) = html_h1(children_maker(); kwargs...) function html_img(; kwargs...) - available_props = Set(Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :alt, :crossOrigin, :height, :sizes, :src, :srcSet, :useMap, :width, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state]) - wild_props = Set(Symbol[Symbol("data-"), Symbol("aria-")]) - wild_regs = r"^(?data-|aria-)" + available_props = Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :alt, :crossOrigin, :height, :sizes, :src, :srcSet, :useMap, :width, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state] + wild_props = Symbol[Symbol("data-"), Symbol("aria-")] - result = Component("Img", "dash_html_components", Dict{Symbol, Any}(), available_props, Set(Symbol[Symbol("data-"), Symbol("aria-")])) - - for (prop, value) = pairs(kwargs) - m = match(wild_regs, string(prop)) - if (length(wild_props) == 0 || isnothing(m)) && !(prop in available_props) - throw(ArgumentError("Invalid property $(string(prop)) for component " * "html_img")) - end - - push!(result.props, prop => Front.to_dash(value)) - end - -return result + return Component("html_h1", "Img", "dash_html_components", available_props, wild_props; kwargs...) end -function html_img(children::Any; kwargs...) -result = html_img(;kwargs...) -push!(result.props, :children => Front.to_dash(children)) -return result -end +html_img(children::Any; kwargs...) = html_img(;kwargs..., children = children) html_img(children_maker::Function; kwargs...) = html_img(children_maker(); kwargs...) function html_a(; kwargs...) - available_props = Set(Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :download, :href, :hrefLang, :media, :rel, :shape, :target, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state]) - wild_props = Set(Symbol[Symbol("data-"), Symbol("aria-")]) - wild_regs = r"^(?data-|aria-)" - - result = Component("A", "dash_html_components", Dict{Symbol, Any}(), available_props, Set(Symbol[Symbol("data-"), Symbol("aria-")])) - - for (prop, value) = pairs(kwargs) - m = match(wild_regs, string(prop)) - if (length(wild_props) == 0 || isnothing(m)) && !(prop in available_props) - throw(ArgumentError("Invalid property $(string(prop)) for component " * "html_a")) - end + available_props = Symbol[:children, :id, :n_clicks, :n_clicks_timestamp, :key, :role, :download, :href, :hrefLang, :media, :rel, :shape, :target, :accessKey, :className, :contentEditable, :contextMenu, :dir, :draggable, :hidden, :lang, :spellCheck, :style, :tabIndex, :title, :loading_state] + wild_props = Symbol[Symbol("data-"), Symbol("aria-")] - push!(result.props, prop => Front.to_dash(value)) - end - -return result + return Component("html_a", "A", "dash_html_components", available_props, wild_props; kwargs...) end -function html_a(children::Any; kwargs...) -result = html_a(;kwargs...) -push!(result.props, :children => Front.to_dash(children)) -return result -end +html_a(children::Any; kwargs...) = html_a(;kwargs..., children = children) html_a(children_maker::Function; kwargs...) = html_a(children_maker(); kwargs...) function dcc_input(; kwargs...) - available_props = Set(Symbol[:id, :value, :style, :className, :debounce, :type, :autoComplete, :autoFocus, :disabled, :inputMode, :list, :max, :maxLength, :min, :minLength, :multiple, :name, :pattern, :placeholder, :readOnly, :required, :selectionDirection, :selectionEnd, :selectionStart, :size, :spellCheck, :step, :n_submit, :n_submit_timestamp, :n_blur, :n_blur_timestamp, :loading_state, :persistence, :persisted_props, :persistence_type]) - wild_props = Set(Symbol[]) - wild_regs = r"^(?)" - - result = Component("Input", "dash_core_components", Dict{Symbol, Any}(), available_props, Set(Symbol[])) + available_props = Symbol[:id, :value, :style, :className, :debounce, :type, :autoComplete, :autoFocus, :disabled, :inputMode, :list, :max, :maxLength, :min, :minLength, :multiple, :name, :pattern, :placeholder, :readOnly, :required, :selectionDirection, :selectionEnd, :selectionStart, :size, :spellCheck, :step, :n_submit, :n_submit_timestamp, :n_blur, :n_blur_timestamp, :loading_state, :persistence, :persisted_props, :persistence_type] + wild_props = Symbol[] - for (prop, value) = pairs(kwargs) - m = match(wild_regs, string(prop)) - if (length(wild_props) == 0 || isnothing(m)) && !(prop in available_props) - throw(ArgumentError("Invalid property $(string(prop)) for component " * "dcc_input")) - end - - push!(result.props, prop => Front.to_dash(value)) - end - -return result + return Component("dcc_input", "Input", "dash_core_components", available_props, wild_props; kwargs...) end -function dcc_input(children::Any; kwargs...) -result = dcc_input(;kwargs...) -push!(result.props, :children => Front.to_dash(children)) -return result -end +dcc_input(children::Any; kwargs...) = dcc_input(;kwargs..., children = children) dcc_input(children_maker::Function; kwargs...) = dcc_input(children_maker(); kwargs...) function dcc_graph(; kwargs...) - available_props = Set(Symbol[:id, :responsive, :clickData, :clickAnnotationData, :hoverData, :clear_on_unhover, :selectedData, :relayoutData, :extendData, :restyleData, :figure, :style, :className, :animate, :animation_options, :config, :loading_state]) - wild_props = Set(Symbol[]) - wild_regs = r"^(?)" + available_props = Symbol[:id, :responsive, :clickData, :clickAnnotationData, :hoverData, :clear_on_unhover, :selectedData, :relayoutData, :extendData, :restyleData, :figure, :style, :className, :animate, :animation_options, :config, :loading_state] + wild_props = Symbol[] - result = Component("Graph", "dash_core_components", Dict{Symbol, Any}(), available_props, Set(Symbol[])) - - for (prop, value) = pairs(kwargs) - m = match(wild_regs, string(prop)) - if (length(wild_props) == 0 || isnothing(m)) && !(prop in available_props) - throw(ArgumentError("Invalid property $(string(prop)) for component " * "dcc_graph")) - end - - push!(result.props, prop => Front.to_dash(value)) - end - -return result + return Component("dcc_graph", "Graph", "dash_core_components", available_props, wild_props; kwargs...) end -function dcc_graph(children::Any; kwargs...) -result = dcc_graph(;kwargs...) -push!(result.props, :children => Front.to_dash(children)) -return result -end +dcc_graph(children::Any; kwargs...) = dcc_graph(kwargs..., children = children) dcc_graph(children_maker::Function; kwargs...) = dcc_graph(children_maker(); kwargs...) -end +end \ No newline at end of file diff --git a/test/core.jl b/test/core.jl index 790c2ae..757b719 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1,33 +1,28 @@ import HTTP, JSON2 using Test using Dash -using Inflate @testset "Components" begin a_comp = html_a("test", id = "test-a") - @test a_comp.type == "A" - @test a_comp.namespace == "dash_html_components" - @test a_comp.props[:id] == "test-a" - @test a_comp.props[:children] == "test" + @test a_comp.id == "test-a" + @test a_comp.children == "test" input_comp = dcc_input(id = "test-input", type="text") - @test input_comp.type == "Input" - @test input_comp.namespace == "dash_core_components" - @test input_comp.props[:id] == "test-input" - @test input_comp.props[:type] == "text" + @test input_comp.id == "test-input" + @test input_comp.type == "text" - @test_throws ArgumentError html_a(undefined_prop = "rrrr") + @test_throws ErrorException html_a(undefined_prop = "rrrr") component_with_children = html_div() do html_a("fffff"), html_h1("fffff") end - @test haskey(component_with_children.props, :children) - @test component_with_children.props[:children] isa Tuple{Component, Component} - @test length(component_with_children.props[:children]) == 2 - @test component_with_children.props[:children][1].type == "A" - @test component_with_children.props[:children][2].type == "H1" + @test !isnothing(component_with_children.children) + @test component_with_children.children isa Tuple{Component, Component} + @test length(component_with_children.children) == 2 + @test DashBase.get_type(component_with_children.children[1]) == "A" + @test DashBase.get_type(component_with_children.children[2]) == "H1" end @@ -173,33 +168,6 @@ end end -@testset "HTTP Compression" begin - # test compression of assets - app = dash(assets_folder = "assets_compressed", compress = true) - app.layout = html_div() - handler = Dash.make_handler(app) - - # ensure no compression of assets when Accept-Encoding not passed - request = HTTP.Request("GET", "/assets/bootstrap.css") - body = read("assets_compressed/bootstrap.css", String) - response = HTTP.handle(handler, request) - @test String(response.body) == body - @test !in("Content-Encoding"=>"gzip", response.headers) - - # ensure compression when Accept-Encoding = "gzip" - request = HTTP.Request("GET", "/assets/bootstrap.css", ["Accept-Encoding"=>"gzip"]) - response = HTTP.handle(handler, request) - @test String(inflate_gzip(response.body)) == body - @test String(response.body) != body - @test in("Content-Encoding"=>"gzip", response.headers) - - # test cases for compress = false - app = dash(assets_folder = "assets", compress=false) - app.layout = html_div() do - html_div("test") - end -end - @testset "layout validation" begin app = dash(assets_folder = "assets_compressed", compress = true) @test_throws ErrorException make_handler(app)