Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Metabase
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Engineering Digital Service
Metabase
Commits
87a835f1
Commit
87a835f1
authored
6 years ago
by
Simon Belak
Browse files
Options
Downloads
Patches
Plain Diff
Fix rule loading
parent
db39083e
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/metabase/automagic_dashboards/core.clj
+67
-57
67 additions, 57 deletions
src/metabase/automagic_dashboards/core.clj
src/metabase/automagic_dashboards/rules.clj
+12
-5
12 additions, 5 deletions
src/metabase/automagic_dashboards/rules.clj
with
79 additions
and
62 deletions
src/metabase/automagic_dashboards/core.clj
+
67
−
57
View file @
87a835f1
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
[
metabase.util
:as
u
]
[
metabase.util
:as
u
]
[
puppetlabs.i18n.core
:as
i18n
:refer
[
tru
]]
[
puppetlabs.i18n.core
:as
i18n
:refer
[
tru
]]
[
ring.util.codec
:as
codec
]
[
ring.util.codec
:as
codec
]
[
schema.core
:as
s
]
[
toucan.db
:as
db
]))
[
toucan.db
:as
db
]))
(
def
^
:private
public-endpoint
"/auto/dashboard/"
)
(
def
^
:private
public-endpoint
"/auto/dashboard/"
)
...
@@ -50,7 +51,7 @@
...
@@ -50,7 +51,7 @@
:source
table
:source
table
:database
(
:db_id
table
)
:database
(
:db_id
table
)
:url
(
format
"%stable/%s"
public-endpoint
(
u/get-id
table
))
:url
(
format
"%stable/%s"
public-endpoint
(
u/get-id
table
))
:rules-prefix
"table"
})
:rules-prefix
[
"table"
]
})
(
defmethod
->root
(
type
Segment
)
(
defmethod
->root
(
type
Segment
)
[
segment
]
[
segment
]
...
@@ -61,7 +62,7 @@
...
@@ -61,7 +62,7 @@
:database
(
:db_id
table
)
:database
(
:db_id
table
)
:query-filter
(
->
segment
:definition
:filter
)
:query-filter
(
->
segment
:definition
:filter
)
:url
(
format
"%ssegment/%s"
public-endpoint
(
u/get-id
segment
))
:url
(
format
"%ssegment/%s"
public-endpoint
(
u/get-id
segment
))
:rules-prefix
"table"
}))
:rules-prefix
[
"table"
]
}))
(
defmethod
->root
(
type
Metric
)
(
defmethod
->root
(
type
Metric
)
[
metric
]
[
metric
]
...
@@ -71,7 +72,7 @@
...
@@ -71,7 +72,7 @@
:source
table
:source
table
:database
(
:db_id
table
)
:database
(
:db_id
table
)
:url
(
format
"%smetric/%s"
public-endpoint
(
u/get-id
metric
))
:url
(
format
"%smetric/%s"
public-endpoint
(
u/get-id
metric
))
:rules-prefix
"metric"
}))
:rules-prefix
[
"metric"
]
}))
(
defmethod
->root
(
type
Field
)
(
defmethod
->root
(
type
Field
)
[
field
]
[
field
]
...
@@ -81,7 +82,7 @@
...
@@ -81,7 +82,7 @@
:source
table
:source
table
:database
(
:db_id
table
)
:database
(
:db_id
table
)
:url
(
format
"%sfield/%s"
public-endpoint
(
u/get-id
field
))
:url
(
format
"%sfield/%s"
public-endpoint
(
u/get-id
field
))
:rules-prefix
"field"
}))
:rules-prefix
[
"field"
]
}))
(
defmulti
(
defmulti
^
{
:doc
"Get a reference for a given model to be injected into a template
^
{
:doc
"Get a reference for a given model to be injected into a template
...
@@ -420,14 +421,15 @@
...
@@ -420,14 +421,15 @@
(
assoc
:score
score
(
assoc
:score
score
:dataset_query
query
))))))))
:dataset_query
query
))))))))
(
def
^
:private
^
{
:arglists
'
([
rule
])}
rule-specificity
(
s/defn
^
:private
rule-specificity
(
comp
(
partial
transduce
(
map
(
comp
count
ancestors
))
+
)
:applies_to
))
[
rule
:-
rules/Rule
]
(
transduce
(
map
(
comp
count
ancestors
))
+
(
:applies_to
rule
)))
(
defn
-
matching-rules
(
s/
defn
^
:private
matching-rules
"Return matching rules orderd by specificity.
"Return matching rules orderd by specificity.
Most specific is defined as entity type specification the longest ancestor
Most specific is defined as entity type specification the longest ancestor
chain."
chain."
[
rules
{
:keys
[
source
entity
]}]
[
rules
:-
[
rules/Rule
]
,
{
:keys
[
source
entity
]}]
(
let
[
table-type
(
or
(
:entity_type
source
)
:entity/GenericTable
)]
(
let
[
table-type
(
or
(
:entity_type
source
)
:entity/GenericTable
)]
(
->>
rules
(
->>
rules
(
filter
(
fn
[{
:keys
[
applies_to
]}]
(
filter
(
fn
[{
:keys
[
applies_to
]}]
...
@@ -479,8 +481,8 @@
...
@@ -479,8 +481,8 @@
[
context
_
]
[
context
_
]
context
)
context
)
(
defn
-
make-context
(
s/
defn
^
:private
make-context
[
root
rule
]
[
root
,
rule
:-
rules/Rule
]
{
:pre
[(
:source
root
)]}
{
:pre
[(
:source
root
)]}
(
let
[
source
(
:source
root
)
(
let
[
source
(
:source
root
)
tables
(
concat
[
source
]
(
when
(
instance?
(
type
Table
)
source
)
tables
(
concat
[
source
]
(
when
(
instance?
(
type
Table
)
source
)
...
@@ -524,10 +526,10 @@
...
@@ -524,10 +526,10 @@
vals
vals
(
apply
concat
)))
(
apply
concat
)))
(
defn
-
make-dashboard
(
s/
defn
^
:private
make-dashboard
([
root
rule
]
([
root
,
rule
:-
rules/Rule
]
(
make-dashboard
root
rule
{
:tables
[(
:source
root
)]}))
(
make-dashboard
root
rule
{
:tables
[(
:source
root
)]}))
([
root
rule
context
]
([
root
,
rule
:-
rules/Rule,
context
]
(
let
[
this
{
"this"
(
->
root
(
let
[
this
{
"this"
(
->
root
:entity
:entity
(
assoc
:full-name
(
:full-name
root
)))}]
(
assoc
:full-name
(
:full-name
root
)))}]
...
@@ -540,8 +542,8 @@
...
@@ -540,8 +542,8 @@
(
update
:groups
(
partial
fill-templates
:string
context
{}))
(
update
:groups
(
partial
fill-templates
:string
context
{}))
(
assoc
:refinements
(
:cell-query
root
))))))
(
assoc
:refinements
(
:cell-query
root
))))))
(
defn
-
apply-rule
(
s/
defn
^
:private
apply-rule
[
root
rule
]
[
root
,
rule
:-
rules/Rule
]
(
let
[
context
(
make-context
root
rule
)
(
let
[
context
(
make-context
root
rule
)
dashboard
(
make-dashboard
root
rule
context
)
dashboard
(
make-dashboard
root
rule
context
)
filters
(
->>
rule
filters
(
->>
rule
...
@@ -568,7 +570,7 @@
...
@@ -568,7 +570,7 @@
[
entity
]
[
entity
]
(
let
[
root
(
->root
entity
)
(
let
[
root
(
->root
entity
)
rule
(
->>
root
rule
(
->>
root
(
matching-rules
(
rules/get-rules
[
(
:rules-prefix
root
)
]
))
(
matching-rules
(
rules/get-rules
(
:rules-prefix
root
)))
first
)
first
)
dashboard
(
make-dashboard
root
rule
)]
dashboard
(
make-dashboard
root
rule
)]
{
:url
(
:url
root
)
{
:url
(
:url
root
)
...
@@ -587,9 +589,9 @@
...
@@ -587,9 +589,9 @@
(
take
n
)
(
take
n
)
(
map
->related-entity
)))))
(
map
->related-entity
)))))
(
defn
-
indepth
(
s/
defn
^
:private
indepth
[
root
rule
]
[
root
,
rule
:-
rules/Rule
]
(
->>
(
rules/get-rules
[
(
:rules-prefix
root
)
(
:rule
rule
)])
(
->>
(
rules/get-rules
(
concat
(
:rules-prefix
root
)
[
(
:rule
rule
)])
)
(
keep
(
fn
[
indepth
]
(
keep
(
fn
[
indepth
]
(
when-let
[[
dashboard
_
]
(
apply-rule
root
indepth
)]
(
when-let
[[
dashboard
_
]
(
apply-rule
root
indepth
)]
{
:title
((
some-fn
:short-title
:title
)
dashboard
)
{
:title
((
some-fn
:short-title
:title
)
dashboard
)
...
@@ -598,8 +600,8 @@
...
@@ -598,8 +600,8 @@
(
:rule
indepth
))})))
(
:rule
indepth
))})))
(
take
max-related
)))
(
take
max-related
)))
(
defn
-
related
(
s/
defn
^
:private
related
[
root
rule
]
[
root
,
rule
:-
rules/Rule
]
(
let
[
indepth
(
indepth
root
rule
)]
(
let
[
indepth
(
indepth
root
rule
)]
{
:indepth
indepth
{
:indepth
indepth
:tables
(
take
(
-
max-related
(
count
indepth
))
(
others
root
))}))
:tables
(
take
(
-
max-related
(
count
indepth
))
(
others
root
))}))
...
@@ -607,40 +609,48 @@
...
@@ -607,40 +609,48 @@
(
defn-
automagic-dashboard
(
defn-
automagic-dashboard
"Create dashboards for table `root` using the best matching heuristics."
"Create dashboards for table `root` using the best matching heuristics."
[{
:keys
[
rule
show
rules-prefix
query-filter
cell-query
full-name
]
:as
root
}]
[{
:keys
[
rule
show
rules-prefix
query-filter
cell-query
full-name
]
:as
root
}]
(
when-let
[[
dashboard
rule
]
(
if
rule
(
if-let
[[
dashboard
rule
]
(
if
rule
(
apply-rule
root
(
rules/get-rule
rule
))
(
apply-rule
root
(
rules/get-rule
rule
))
(
->>
root
(
->>
root
(
matching-rules
(
rules/get-rules
[
rules-prefix
]))
(
matching-rules
(
rules/get-rules
rules-prefix
))
(
keep
(
partial
apply-rule
root
))
(
keep
(
partial
apply-rule
root
))
;; `matching-rules` returns an `ArraySeq` (via `sort-by`) so
;; `matching-rules` returns an `ArraySeq` (via `sort-by`) so
;; `first` realises one element at a time (no chunking).
;; `first` realises one element at a time (no chunking).
first
))]
first
))]
(
log/info
(
format
"Applying heuristic %s to %s."
(
:rule
rule
)
full-name
))
(
do
(
log/info
(
format
"Dimensions bindings:\n%s"
(
log/info
(
format
"Applying heuristic %s to %s."
(
:rule
rule
)
full-name
))
(
->>
dashboard
(
log/info
(
format
"Dimensions bindings:\n%s"
:context
(
->>
dashboard
:dimensions
:context
(
m/map-vals
#
(
update
%
:matches
(
partial
map
:name
)))
:dimensions
u/pprint-to-str
)))
(
m/map-vals
#
(
update
%
:matches
(
partial
map
:name
)))
(
log/info
(
format
"Using definitions:\nMetrics:\n%s\nFilters:\n%s"
u/pprint-to-str
)))
(
->
dashboard
:context
:metrics
u/pprint-to-str
)
(
log/info
(
format
"Using definitions:\nMetrics:\n%s\nFilters:\n%s"
(
->
dashboard
:context
:filters
u/pprint-to-str
)))
(
->
dashboard
:context
:metrics
u/pprint-to-str
)
(
->
(
cond->
dashboard
(
->
dashboard
:context
:filters
u/pprint-to-str
)))
(
or
query-filter
cell-query
)
(
->
(
cond->
dashboard
(
assoc
:title
(
str
(
tru
"A closer look at "
)
full-name
)))
(
or
query-filter
cell-query
)
(
populate/create-dashboard
(
or
show
max-cards
))
(
assoc
:title
(
str
(
tru
"A closer look at "
)
full-name
)))
(
assoc
:related
(
->
(
related
root
rule
)
(
populate/create-dashboard
(
or
show
max-cards
))
(
assoc
:more
(
if
(
and
(
->
dashboard
(
assoc
:related
(
->
(
related
root
rule
)
:cards
(
assoc
:more
(
if
(
and
(
->
dashboard
count
:cards
(
>
max-cards
))
count
(
not=
show
:all
))
(
>
max-cards
))
[{
:title
(
tru
"Show more about this"
)
(
not=
show
:all
))
:description
nil
[{
:title
(
tru
"Show more about this"
)
:table
(
:source
root
)
:description
nil
:url
(
format
"%s#show=all"
:table
(
:source
root
)
(
:url
root
))}]
:url
(
format
"%s#show=all"
[])))))))
(
:url
root
))}]
[]))))))
(
throw
(
ex-info
(
format
"Can't create dashboard for %s"
full-name
)
{
:path
(
or
rule
rules-prefix
)
:path-type
(
if
rule
:path
:prefix
)
:available-rules
(
map
:rule
(
or
(
some->
rule
rules/get-rule
vector
)
(
rules/get-rules
rules-prefix
)))}))))
(
def
^
:private
^
{
:arglists
'
([
card
])}
table-like?
(
def
^
:private
^
{
:arglists
'
([
card
])}
table-like?
(
comp
empty?
#
(
qp.util/get-in-normalized
%
[
:dataset_query
:query
:aggregation
])))
(
comp
empty?
#
(
qp.util/get-in-normalized
%
[
:dataset_query
:query
:aggregation
])))
...
@@ -698,7 +708,7 @@
...
@@ -698,7 +708,7 @@
(
u/get-id
card
)
(
u/get-id
card
)
(
encode-base64-json
cell-query
))
(
encode-base64-json
cell-query
))
(
format
"%squestion/%s"
public-endpoint
(
u/get-id
card
)))
(
format
"%squestion/%s"
public-endpoint
(
u/get-id
card
)))
:rules-prefix
"table"
}
:rules-prefix
[
"table"
]
}
opts
)))
opts
)))
nil
))
nil
))
...
@@ -731,7 +741,7 @@
...
@@ -731,7 +741,7 @@
(
encode-base64-json
cell-query
))
(
encode-base64-json
cell-query
))
(
format
"%sadhoc/%s"
public-endpoint
(
format
"%sadhoc/%s"
public-endpoint
(
encode-base64-json
query
)))
(
encode-base64-json
query
)))
:rules-prefix
"table"
}
:rules-prefix
[
"table"
]
}
(
update
opts
:cell-query
merge-filter-clauses
(
update
opts
:cell-query
merge-filter-clauses
(
qp.util/get-in-normalized
query
[
:dataset_query
:query
:filter
])))))
(
qp.util/get-in-normalized
query
[
:dataset_query
:query
:filter
])))))
nil
))
nil
))
...
...
This diff is collapsed.
Click to expand it.
src/metabase/automagic_dashboards/rules.clj
+
12
−
5
View file @
87a835f1
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
[
core
:as
s
]]
[
core
:as
s
]]
[
yaml.core
:as
yaml
])
[
yaml.core
:as
yaml
])
(
:import
java.nio.file.Path
java.nio.file.FileSystems
java.nio.file.FileSystem
(
:import
java.nio.file.Path
java.nio.file.FileSystems
java.nio.file.FileSystem
java.nio.file.Files
))
java.nio.file.Files
))
(
def
^
Long
^
:const
max-score
(
def
^
Long
^
:const
max-score
"Maximal (and default) value for heuristics scores."
"Maximal (and default) value for heuristics scores."
...
@@ -186,7 +186,8 @@
...
@@ -186,7 +186,8 @@
schema
schema
(
partition
2
constraints
)))
(
partition
2
constraints
)))
(
def
^
:private
Rules
(
def
Rule
"Rules defining an automagic dashboard."
(
constrained-all
(
constrained-all
{(
s/required-key
:title
)
s/Str
{(
s/required-key
:title
)
s/Str
(
s/required-key
:dimensions
)
[
Dimension
]
(
s/required-key
:dimensions
)
[
Dimension
]
...
@@ -234,7 +235,7 @@
...
@@ -234,7 +235,7 @@
(
def
^
:private
rules-validator
(
def
^
:private
rules-validator
(
sc/coercer!
(
sc/coercer!
Rule
s
Rule
{[
s/Str
]
ensure-seq
{[
s/Str
]
ensure-seq
[
OrderByPair
]
ensure-seq
[
OrderByPair
]
ensure-seq
OrderByPair
(
fn
[
x
]
OrderByPair
(
fn
[
x
]
...
@@ -277,7 +278,7 @@
...
@@ -277,7 +278,7 @@
(
def
^
:private
rules-dir
"automagic_dashboards/"
)
(
def
^
:private
rules-dir
"automagic_dashboards/"
)
(
def
^
:private
^
{
:arglists
'
([
f
])}
file->entity-type
(
def
^
:private
^
{
:arglists
'
([
f
])}
file->entity-type
(
comp
(
partial
re-find
#
".+(?=\.yaml)"
)
str
(
memfn
^
Path
getFileName
)))
(
comp
(
partial
re-find
#
".+(?=\.yaml
$
)"
)
str
(
memfn
^
Path
getFileName
)))
(
defn-
load-rule
(
defn-
load-rule
[
^
Path
f
]
[
^
Path
f
]
...
@@ -300,6 +301,12 @@
...
@@ -300,6 +301,12 @@
e
)))
e
)))
nil
)))
nil
)))
(
defn-
trim-trailing-slash
[
s
]
(
if
(
str/ends-with?
s
"/"
)
(
subs
s
0
(
->
s
count
dec
))
s
))
(
defn-
load-rule-dir
(
defn-
load-rule-dir
([
dir
]
(
load-rule-dir
dir
[]
{}))
([
dir
]
(
load-rule-dir
dir
[]
{}))
([
dir
path
rules
]
([
dir
path
rules
]
...
@@ -307,7 +314,7 @@
...
@@ -307,7 +314,7 @@
(
reduce
(
fn
[
rules
^
Path
f
]
(
reduce
(
fn
[
rules
^
Path
f
]
(
cond
(
cond
(
Files/isDirectory
f
(
into-array
java.nio.file.LinkOption
[]))
(
Files/isDirectory
f
(
into-array
java.nio.file.LinkOption
[]))
(
load-rule-dir
f
(
conj
path
(
str
(
.getFileName
f
)
))
rules
)
(
load-rule-dir
f
(
->>
f
(
.getFileName
)
str
trim-trailing-slash
(
conj
path
))
rules
)
(
file->entity-type
f
)
(
file->entity-type
f
)
(
assoc-in
rules
(
concat
path
[(
file->entity-type
f
)
::leaf
])
(
load-rule
f
))
(
assoc-in
rules
(
concat
path
[(
file->entity-type
f
)
::leaf
])
(
load-rule
f
))
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment