jekyll-open-sdg-plugins 1.1.0 → 1.2.0.pre.beta5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e6f79d3292ae608202621743899fe24604ee67fc7bcc9ca90d26e91bf18e8d6
4
- data.tar.gz: e09f66ec6f34a74e8b29d07f9dc75dcd2c3a4484daa3d02db45eb5140f2fd637
3
+ metadata.gz: 55f3d80d4acc19d67bb4d70f17c1297f04ec33d313e7a26e34a2f82e63c8c91c
4
+ data.tar.gz: 524cf624a527082236c885139cc0b2582c8b9ace8cf7d57292e2c74e8e076ebe
5
5
  SHA512:
6
- metadata.gz: d217ea0ac1fecaaf2e4d83f7d39d094be1f6d34277a52b5c34c0aa369effefb7589ec44e76d41d87ce437c84f0d1a6bcb47c657c04db751dac93fdbcb586bc19
7
- data.tar.gz: 94d80452821f6793932b5be5342d6d99814caf52dd27cd5b27e000fe67b1893364d6da9c47bc1327743125e5b01c2a49431d4405f0c075a62dd77ff182a25819
6
+ metadata.gz: d7da9b8f7fb2399ec8de5b90866fe7fab567ac4feeba5f4a91f6c4a7e550d498506caf649b6153c13befe51bcc80d71fc2da22ba74f62ac45e4cb47dfb246ba1
7
+ data.tar.gz: 2497c3cfec27dd90cab528becda64da55f14521f6e5cfbfb0b6399df14072d96cd930e8675b6c8d5959d850c5c2b658c31da4510c6ad1515d3c88f61399b41c5
@@ -14,4 +14,5 @@ Gem::Specification.new do |spec|
14
14
  spec.require_paths = ["lib"]
15
15
  spec.add_dependency "jekyll", "~> 3.0"
16
16
  spec.add_dependency "deep_merge", "~> 1.2"
17
+ spec.add_dependency "json_schemer", "~> 0.2"
17
18
  end
@@ -1,5 +1,6 @@
1
1
  require_relative "jekyll-open-sdg-plugins/version"
2
2
  require_relative "jekyll-open-sdg-plugins/site_configuration"
3
+ require_relative "jekyll-open-sdg-plugins/validate_site_config"
3
4
  require_relative "jekyll-open-sdg-plugins/fetch_remote_data"
4
5
  require_relative "jekyll-open-sdg-plugins/translate_key"
5
6
  require_relative "jekyll-open-sdg-plugins/translate_date"
@@ -9,6 +10,7 @@ require_relative "jekyll-open-sdg-plugins/create_goals"
9
10
  require_relative "jekyll-open-sdg-plugins/create_pages"
10
11
  require_relative "jekyll-open-sdg-plugins/sdg_variables"
11
12
  require_relative "jekyll-open-sdg-plugins/search_index"
13
+ require_relative "jekyll-open-sdg-plugins/validate_indicator_config"
12
14
 
13
15
  module JekyllOpenSdgPlugins
14
16
  end
@@ -8,7 +8,7 @@ module JekyllOpenSdgPlugins
8
8
 
9
9
  def generate(site)
10
10
  # If site.create_goals is set, create goals per the metadata.
11
- if site.config['languages'] and site.config['create_goals']
11
+ if site.config['languages'] and site.config['create_goals'] and site.config['create_goals'].key?('layout') and site.config['create_goals']['layout'] != ''
12
12
  # Compile the list of goals.
13
13
  goals = {}
14
14
  # Are we using translated builds?
@@ -27,10 +27,7 @@ module JekyllOpenSdgPlugins
27
27
  goals[goal] = true
28
28
  end
29
29
  # Decide what layout to use for the goal pages.
30
- layout = 'goal'
31
- if site.config['create_goals'].key?('layout')
32
- layout = site.config['create_goals']['layout']
33
- end
30
+ layout = site.config['create_goals']['layout']
34
31
  # See if we need to "map" any language codes.
35
32
  languages_public = Hash.new
36
33
  if site.config['languages_public']
@@ -8,12 +8,9 @@ module JekyllOpenSdgPlugins
8
8
 
9
9
  def generate(site)
10
10
  # If site.create_indicators is set, create indicators per the metadata.
11
- if site.config['languages'] and site.config['create_indicators']
11
+ if site.config['languages'] and site.config['create_indicators'] and site.config['create_indicators'].key?('layout') and site.config['create_indicators']['layout'] != ''
12
12
  # Decide what layout to use for the indicator pages.
13
- layout = 'indicator'
14
- if site.config['create_indicators'].key?('layout')
15
- layout = site.config['create_indicators']['layout']
16
- end
13
+ layout = site.config['create_indicators']['layout']
17
14
  # See if we need to "map" any language codes.
18
15
  languages_public = Hash.new
19
16
  if site.config['languages_public']
@@ -43,6 +40,39 @@ module JekyllOpenSdgPlugins
43
40
  site.collections['indicators'].docs << IndicatorPage.new(site, site.source, dir, inid, language, layout)
44
41
  end
45
42
  end
43
+ # Create the indicator configuration pages.
44
+ if site.config['create_config_forms'] && site.config['create_config_forms'].key?('layout') && site.config['create_config_forms']['layout'] != ''
45
+ metadata = {}
46
+ layout = site.config['create_config_forms']['layout']
47
+ if opensdg_translated_builds(site)
48
+ if site.data.has_key?('untranslated')
49
+ metadata = site.data['untranslated']['meta']
50
+ else
51
+ default_language = site.config['languages'][0]
52
+ metadata = site.data[default_language]['meta']
53
+ end
54
+ else
55
+ metadata = site.data['meta']
56
+ end
57
+ # Loop through the indicators (using metadata as a list).
58
+ if !metadata.empty?
59
+ # Loop through the languages.
60
+ site.config['languages'].each_with_index do |language, index|
61
+ # Get the "public language" (for URLs) which may be different.
62
+ language_public = language
63
+ if languages_public[language]
64
+ language_public = languages_public[language]
65
+ end
66
+ metadata.each do |inid, meta|
67
+ dir = File.join('config', inid)
68
+ if index != 0
69
+ dir = File.join(language_public, 'config', inid)
70
+ end
71
+ site.collections['pages'].docs << IndicatorConfigPage.new(site, site.source, dir, inid, language, meta, layout)
72
+ end
73
+ end
74
+ end
75
+ end
46
76
  end
47
77
  end
48
78
  end
@@ -64,4 +94,24 @@ module JekyllOpenSdgPlugins
64
94
  self.data['indicator'] = self.data['indicator_number']
65
95
  end
66
96
  end
97
+
98
+ # A Page subclass used in the `CreateIndicators` class.
99
+ class IndicatorConfigPage < Jekyll::Page
100
+ def initialize(site, base, dir, inid, language, meta, layout)
101
+ @site = site
102
+ @base = base
103
+ @dir = dir
104
+ @name = 'index.html'
105
+
106
+ self.process(@name)
107
+ self.data = {}
108
+ self.data['language'] = language
109
+ self.data['indicator_number'] = inid.gsub('-', '.')
110
+ self.data['config_type'] = 'indicator'
111
+ self.data['layout'] = layout
112
+ self.data['meta'] = meta
113
+ self.data['title'] = 'Open SDG indicator configuration: ' + self.data['indicator_number']
114
+ self.data['config_filename'] = inid + '.yml'
115
+ end
116
+ end
67
117
  end
@@ -61,6 +61,23 @@ module JekyllOpenSdgPlugins
61
61
  pages = site.config['create_pages']
62
62
  end
63
63
 
64
+ # Clone pages so that we don't edit the original.
65
+ pages = pages.clone
66
+
67
+ # Hardcode the site configuration page if it's not already there.
68
+ config_page = pages.find { |page| page['layout'] == 'config-builder' }
69
+ if config_page == nil
70
+ if site.config['create_config_forms'] && site.config['create_config_forms'].key?('layout') && site.config['create_config_forms']['layout'] != ''
71
+ pages.push({
72
+ 'folder' => '/config',
73
+ 'layout' => site.config['create_config_forms']['layout'],
74
+ 'title' => 'Open SDG site configuration',
75
+ 'config_type' => 'site',
76
+ 'config_filename' => 'site_config.yml'
77
+ })
78
+ end
79
+ end
80
+
64
81
  # See if we need to "map" any language codes.
65
82
  languages_public = Hash.new
66
83
  if site.config['languages_public']
@@ -92,7 +109,7 @@ module JekyllOpenSdgPlugins
92
109
  @site = site
93
110
  @base = base
94
111
 
95
- index_files = (!page.key?('filename') or page['filename'] == 'index.html')
112
+ index_files = (!page.key?('filename') or page['filename'] == 'index.html' or page['filename'] == '')
96
113
  @dir = index_files ? File.join(dir, '/') : dir
97
114
  @name = index_files ? 'index.html' : page['filename']
98
115
 
@@ -22,20 +22,17 @@ module JekyllOpenSdgPlugins
22
22
  'headlines' => 'headline/all.json',
23
23
  'schema' => 'meta/schema.json',
24
24
  'reporting' => 'stats/reporting.json',
25
+ 'disaggregation' => 'stats/disaggregation.json',
25
26
  'translations' => 'translations/translations.json',
26
- 'zip' => 'zip/all_indicators.json'
27
+ 'zip' => 'zip/all_indicators.json',
28
+ 'indicator_downloads' => 'downloads/indicator-downloads.json'
27
29
  }
28
30
  end
29
31
 
30
- # Is this path a remote path?
31
- def is_path_remote(path)
32
- return path.start_with?('http')
33
- end
34
-
35
32
  # Get a build from a local folder on disk or a remote URL on the Internet.
36
33
  def fetch_build(path)
37
34
 
38
- is_remote = is_path_remote(path)
35
+ is_remote = opensdg_is_path_remote(path)
39
36
  build = {}
40
37
  get_endpoints().each do |key, value|
41
38
  endpoint = is_remote ? path + '/' + value : File.join(path, fix_path(value))
@@ -44,8 +41,14 @@ module JekyllOpenSdgPlugins
44
41
  json_file = is_remote ? open(endpoint) : File.open(endpoint)
45
42
  build[key] = JSON.load(json_file)
46
43
  rescue StandardError => e
47
- # For backwards compatibility, we allow 'translations' to be missing.
48
- if key != 'translations'
44
+ # For backwards compatibility, forego the exception in some cases.
45
+ abort_build = true
46
+ if ['translations', 'indicator_downloads', 'disaggregation'].include? key
47
+ abort_build = false
48
+ elsif endpoint.include? '/untranslated/'
49
+ abort_build = false
50
+ end
51
+ if abort_build
49
52
  puts e.message
50
53
  abort 'Unable to read data from: ' + endpoint
51
54
  end
@@ -59,7 +62,7 @@ module JekyllOpenSdgPlugins
59
62
  # translated builds or not.
60
63
  def site_uses_translated_builds(path)
61
64
 
62
- is_remote = is_path_remote(path)
65
+ is_remote = opensdg_is_path_remote(path)
63
66
  endpoints = get_endpoints()
64
67
  # For a quick test, we just use 'meta'.
65
68
  meta = endpoints['meta']
@@ -88,23 +91,30 @@ module JekyllOpenSdgPlugins
88
91
  local = site.config['local_data_folder']
89
92
 
90
93
  if !remote && !local
91
- abort 'Site config must include either "remote_data_prefix" or "local_data_folder".'
94
+ abort 'Site config must include "remote_data_prefix".'
92
95
  end
93
96
 
94
- build_location = remote ? remote : File.join(Dir.pwd, local)
97
+ build_location = remote ? remote : local
98
+ is_remote = opensdg_is_path_remote(build_location)
99
+
100
+ build_location = is_remote ? build_location : File.join(Dir.pwd, build_location)
95
101
  translated_builds = site_uses_translated_builds(build_location)
96
102
 
97
103
  if translated_builds
98
104
  # For translated builds, we get a build for each language, and
99
105
  # place them in "subfolders" (so to speak) of site.data.
100
- site.config['languages'].each do |language|
106
+ subfolders = site.config['languages'].clone
107
+ subfolders.append('untranslated')
108
+ subfolders.each do |language|
101
109
  data_target = site.data[language]
102
- translated_build = remote ? build_location + '/' + language : File.join(build_location, language)
110
+ translated_build = is_remote ? build_location + '/' + language : File.join(build_location, language)
103
111
  data_source = fetch_build(translated_build)
104
- if data_target
105
- data_target.deep_merge(data_source)
106
- else
107
- site.data[language] = data_source
112
+ if !data_source.empty?
113
+ if data_target
114
+ data_target.deep_merge(data_source)
115
+ else
116
+ site.data[language] = data_source
117
+ end
108
118
  end
109
119
  end
110
120
  # We move the language-specific translations to the
@@ -129,7 +139,9 @@ module JekyllOpenSdgPlugins
129
139
  # in the "root" (so to speak) of site.data. Nothing else is needed.
130
140
  target = site.data
131
141
  source = fetch_build(build_location)
132
- target.deep_merge(source)
142
+ if !source.empty?
143
+ target.deep_merge(source)
144
+ end
133
145
  end
134
146
 
135
147
  # Finally support the deprecated 'remote_translations' option.
@@ -162,6 +174,14 @@ module JekyllOpenSdgPlugins
162
174
  source = File.join(Dir.pwd, site.config['local_data_folder'], '.')
163
175
  destination = site.config['destination']
164
176
  FileUtils.cp_r(source, destination)
177
+ # Do the same in the case that "remote_data_prefix" is being used for a local
178
+ # data folder (since "local_data_folder" is deprecated and undocumented).
179
+ elsif site.config['remote_data_prefix']
180
+ if !opensdg_is_path_remote(site.config['remote_data_prefix'])
181
+ source = File.join(Dir.pwd, site.config['remote_data_prefix'], '.')
182
+ destination = site.config['destination']
183
+ FileUtils.cp_r(source, destination)
184
+ end
165
185
  end
166
186
  end
167
187
  end
@@ -92,3 +92,41 @@ def opensdg_languages_public(site)
92
92
  # since the deprecated structure is exactly what this function wants.
93
93
  return languages_public
94
94
  end
95
+
96
+ # Print notices about a validation error.
97
+ def opensdg_validation_error(error)
98
+ if error['type'] == 'required'
99
+ missing = []
100
+ error['schema']['required'].each do |required_property|
101
+ unless error['data'].has_key?(required_property)
102
+ message = 'Missing configuration setting: ' + required_property
103
+ if error['schema'].has_key?('title')
104
+ message += ' (' + error['schema']['title'] + ')'
105
+ end
106
+ opensdg_notice(message)
107
+ end
108
+ end
109
+ else
110
+ message = 'Validation error of type: ' + error['type']
111
+ if error['schema'] && error['schema'].has_key?('title')
112
+ message += ' (' + error['schema']['title'] + ')'
113
+ end
114
+ opensdg_notice(message)
115
+ if error['schema']
116
+ opensdg_notice('Expected schema:')
117
+ puts error['schema'].inspect
118
+ end
119
+ if error['data']
120
+ opensdg_notice('Actual data:')
121
+ puts error['data'].inspect
122
+ end
123
+ end
124
+ end
125
+
126
+ # Is this path a remote path?
127
+ def opensdg_is_path_remote(path)
128
+ if path.nil?
129
+ return false
130
+ end
131
+ return path.start_with?('http')
132
+ end
@@ -0,0 +1,530 @@
1
+ {
2
+ "type": "object",
3
+ "title": "Open SDG indicator configuration",
4
+ "description": "This form will produce an indicator's configuration for your Open SDG implementation.",
5
+ "properties": {
6
+ "computation_units": {
7
+ "type": "string",
8
+ "title": "Unit of measurement",
9
+ "description": "Unit of measurement which displays below the indicator chart.",
10
+ "links": [
11
+ {
12
+ "rel": "More information on the units of measurement setting",
13
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#recommended-special-fields"
14
+ }
15
+ ]
16
+ },
17
+ "copyright": {
18
+ "type": "string",
19
+ "title": "Copyright",
20
+ "description": "Copyright which displays below the indicator chart.",
21
+ "links": [
22
+ {
23
+ "rel": "More information on the copyright setting",
24
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#footer"
25
+ }
26
+ ]
27
+ },
28
+ "data_footnote": {
29
+ "type": "string",
30
+ "format": "markdown",
31
+ "title": "Footnote",
32
+ "description": "Footnote which displays below the indicator chart.",
33
+ "links": [
34
+ {
35
+ "rel": "More information on the footnote setting",
36
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#footer"
37
+ }
38
+ ]
39
+ },
40
+ "data_non_statistical": {
41
+ "title": "Non-statistical data",
42
+ "type": "boolean",
43
+ "description": "Whether the indicator is statistical (can be charted/graphed) or not.",
44
+ "format": "checkbox",
45
+ "links": [
46
+ {
47
+ "rel": "More information the non-statistical setting",
48
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-fields"
49
+ }
50
+ ]
51
+ },
52
+ "data_notice_class": {
53
+ "title": "Data notice - class",
54
+ "type": "string",
55
+ "description": "A CSS class to apply to the data notice for this indicator.",
56
+ "links": [
57
+ {
58
+ "rel": "More information on the data notice setting",
59
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#data-notice"
60
+ }
61
+ ]
62
+ },
63
+ "data_notice_heading": {
64
+ "title": "Data notice - heading",
65
+ "type": "string",
66
+ "description": "A title to display above the data notice for this indicator.",
67
+ "links": [
68
+ {
69
+ "rel": "More information on the data notice heading setting",
70
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#data-notice"
71
+ }
72
+ ]
73
+ },
74
+ "data_notice_text": {
75
+ "title": "Data notice - text",
76
+ "type": "string",
77
+ "format": "markdown",
78
+ "description": "Text to display as a data notice for this indicator, intended to contain very important information which site viewers must keep in mind when using the data provided.",
79
+ "links": [
80
+ {
81
+ "rel": "More information on the data notice text setting",
82
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#data-notice"
83
+ }
84
+ ]
85
+ },
86
+ "data_show_map": {
87
+ "title": "Show map",
88
+ "type": "boolean",
89
+ "description": "Whether the indicator should display a Map tab.",
90
+ "format": "checkbox",
91
+ "links": [
92
+ {
93
+ "rel": "More information on the map setting",
94
+ "href": "https://open-sdg.readthedocs.io/en/latest/maps/#metadata-field-data_show_map"
95
+ }
96
+ ]
97
+ },
98
+ "data_start_values": {
99
+ "options": {"collapsed": true},
100
+ "format": "table",
101
+ "type": "array",
102
+ "title": "Starting values",
103
+ "description": "Disaggregation values for a an indicator to start with already selected",
104
+ "items": {
105
+ "type": "object",
106
+ "title": "Starting value",
107
+ "properties": {
108
+ "field": {
109
+ "type": "string",
110
+ "minLength": 1,
111
+ "title": "Field",
112
+ "description": "The field (column) name."
113
+ },
114
+ "value": {
115
+ "type": "string",
116
+ "minLength": 1,
117
+ "title": "Value",
118
+ "description": "The value in that field to pre-select."
119
+ }
120
+ }
121
+ },
122
+ "links": [
123
+ {
124
+ "rel": "More information on the starting values setting",
125
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#starting-values"
126
+ }
127
+ ]
128
+ },
129
+ "embedded_feature_footer": {
130
+ "type": "string",
131
+ "format": "markdown",
132
+ "title": "Embedded feature - Footer",
133
+ "description": "A footer that displays below the embedded feature. Only used with either embedded_feature_url or embedded_feature_html.",
134
+ "links": [
135
+ {
136
+ "rel": "More information on the embed footer setting",
137
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#embedded-feature-metadata"
138
+ }
139
+ ]
140
+ },
141
+ "embedded_feature_html": {
142
+ "type": "string",
143
+ "format": "textarea",
144
+ "title": "Embedded feature - HTML",
145
+ "description": "Any HTML to display in another tab, after Chart/Table/etc.",
146
+ "links": [
147
+ {
148
+ "rel": "More information on the embed HTML setting",
149
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#embedded-feature-metadata"
150
+ }
151
+ ]
152
+ },
153
+ "embedded_feature_tab_title": {
154
+ "type": "string",
155
+ "title": "Embedded feature - Tab Title",
156
+ "description": "A title for the embedded feature tab (ie, Chart/Table/[this]). Only used with either embedded_feature_url or embedded_feature_html.",
157
+ "links": [
158
+ {
159
+ "rel": "More information on the embed tab title setting",
160
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#embedded-feature-metadata"
161
+ }
162
+ ]
163
+ },
164
+ "embedded_feature_title": {
165
+ "type": "string",
166
+ "title": "Embedded feature - Title",
167
+ "description": "A title that displays above the embedded feature. Only used with either embedded_feature_url or embedded_feature_html.",
168
+ "links": [
169
+ {
170
+ "rel": "More information on the embed title setting",
171
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#embedded-feature-metadata"
172
+ }
173
+ ]
174
+ },
175
+ "embedded_feature_url": {
176
+ "type": "string",
177
+ "format": "url",
178
+ "title": "Embedded feature - URL",
179
+ "description": "Any URL to display as an iframe in another tab, after Chart/Table/etc.",
180
+ "links": [
181
+ {
182
+ "rel": "More information on the embed URL setting",
183
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#embedded-feature-metadata"
184
+ }
185
+ ]
186
+ },
187
+ "expected_disaggregations": {
188
+ "options": {"collapsed": true},
189
+ "format": "table",
190
+ "type": "array",
191
+ "title": "Expected disaggregations",
192
+ "description": "An optional list of disaggregations (ie, data column names) to use when calculating the disaggregation status statistics.",
193
+ "items": {
194
+ "type": "string",
195
+ "title": "Expected disaggregation"
196
+ },
197
+ "links": [
198
+ {
199
+ "rel": "More information on the expected disaggregation setting",
200
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#recommended-special-fields"
201
+ }
202
+ ]
203
+ },
204
+ "graph_annotations": {
205
+ "options": {"collapsed": true},
206
+ "type": "array",
207
+ "title": "Graph annotations",
208
+ "description": "This can be used to add line annotations to the graph, such as target lines to show the progress towards the 2030 goal for an indicator.",
209
+ "items": {
210
+ "type": "object",
211
+ "title": "Graph annotation",
212
+ "properties": {
213
+ "preset": {
214
+ "type": "string",
215
+ "title": "Preset",
216
+ "enum": ["target_line"],
217
+ "description": "A preset bundle of configurations."
218
+ },
219
+ "value": {
220
+ "type": "number",
221
+ "minimum": 0,
222
+ "title": "Value",
223
+ "description": "The value at which to draw the line. For horizontal lines, this number corresponds to your actual data. For vertical lines, this number should be between 0 (the left side of the chart) and the number of years minus 1 (the right side of the chart)."
224
+ },
225
+ "endValue": {
226
+ "type": "number",
227
+ "title": "End value",
228
+ "description": "Optionally add a different ending value for the line."
229
+ },
230
+ "description": {
231
+ "type": "string",
232
+ "title": "Description",
233
+ "description": "A description of the annotation to be read by screenreaders."
234
+ },
235
+ "unit": {
236
+ "type": "string",
237
+ "title": "Unit",
238
+ "description": "The unit of measurement the annotation displays on."
239
+ },
240
+ "series": {
241
+ "type": "string",
242
+ "title": "Series",
243
+ "description": "The series the annotation displays on."
244
+ },
245
+ "mode": {
246
+ "type": "string",
247
+ "title": "Mode",
248
+ "description": "Whether the line will be vertical or horizontal.",
249
+ "enum": ["horizontal", "vertical"]
250
+ },
251
+ "borderColor": {
252
+ "type": "string",
253
+ "format": "color",
254
+ "title": "Line color",
255
+ "description": "The color of the line.",
256
+ "links": [
257
+ {
258
+ "rel": "More information on the border color setting",
259
+ "href": "https://github.com/chartjs/chartjs-plugin-annotation/blob/master/README.md"
260
+ }
261
+ ]
262
+ },
263
+ "borderDash": {
264
+ "type": "string",
265
+ "title": "Line dash type",
266
+ "description": "The type of line dash.",
267
+ "links": [
268
+ {
269
+ "rel": "More information on the line dash setting",
270
+ "href": "https://github.com/chartjs/chartjs-plugin-annotation/blob/master/README.md"
271
+ }
272
+ ]
273
+ },
274
+ "label": {
275
+ "type": "object",
276
+ "title": "Label",
277
+ "description": "A text label for the annotation.",
278
+ "properties": {
279
+ "position": {
280
+ "type": "string",
281
+ "title": "Position",
282
+ "description": "Placement of the label along the line.",
283
+ "enum": [
284
+ "top",
285
+ "bottom",
286
+ "left",
287
+ "right",
288
+ "center"
289
+ ]
290
+ },
291
+ "content": {
292
+ "type": "string",
293
+ "minLength": 1,
294
+ "title": "Content",
295
+ "description": "Text of the line label."
296
+ },
297
+ "fontColor": {
298
+ "type": "string",
299
+ "format": "color",
300
+ "title": "Label color",
301
+ "description": "Color for the label text."
302
+ },
303
+ "backgroundColor": {
304
+ "type": "string",
305
+ "format": "color",
306
+ "default": "#FFFFFFF",
307
+ "title": "Background color",
308
+ "description": "Background color for the label text."
309
+ }
310
+ }
311
+ },
312
+ "highContrast": {
313
+ "type": "object",
314
+ "title": "High contrast options",
315
+ "description": "High-contrast overrides of certain color.",
316
+ "properties": {
317
+ "borderColor": {
318
+ "type": "string",
319
+ "format": "color",
320
+ "default": "#FFFFFF",
321
+ "title": "High-contrast line color",
322
+ "description": "The color of the line in high-contrast mode."
323
+ },
324
+ "label": {
325
+ "type": "object",
326
+ "title": "High contrast label",
327
+ "description": "High-contrast version of the label.",
328
+ "properties": {
329
+ "fontColor": {
330
+ "type": "string",
331
+ "format": "color",
332
+ "default": "#FFFFFF",
333
+ "title": "High-contrast label color",
334
+ "description": "Color for the label text in high-contrast mode."
335
+ },
336
+ "backgroundColor": {
337
+ "type": "string",
338
+ "format": "color",
339
+ "default": "#000000",
340
+ "title": "High-contrast background color",
341
+ "description": "Background color for the label text in high-contrast mode."
342
+ }
343
+ }
344
+ }
345
+ }
346
+ }
347
+ }
348
+ },
349
+ "links": [
350
+ {
351
+ "rel": "More information on the graph annotations setting",
352
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#graph-metadata"
353
+ }
354
+ ]
355
+ },
356
+ "graph_limits": {
357
+ "options": {"collapsed": true},
358
+ "format": "table",
359
+ "type": "array",
360
+ "title": "Graph limits",
361
+ "description": "A list of min/max limits controlling the lowest/highest values to be shown on the y-axis.",
362
+ "items": {
363
+ "type": "object",
364
+ "title": "Graph limit",
365
+ "properties": {
366
+ "minimum": {
367
+ "type": "number",
368
+ "minimum": 0,
369
+ "title": "Minimum",
370
+ "description": "Minimum value for the y axis."
371
+ },
372
+ "maximum": {
373
+ "type": "number",
374
+ "minimum": 0,
375
+ "title": "Maximum",
376
+ "description": "Maximum value for the y axis."
377
+ },
378
+ "unit": {
379
+ "type": "string",
380
+ "title": "Unit",
381
+ "description": "The unit of measurement the limits apply to."
382
+ },
383
+ "series": {
384
+ "type": "string",
385
+ "title": "Series",
386
+ "description": "The series the limits apply to."
387
+ }
388
+ }
389
+ },
390
+ "links": [
391
+ {
392
+ "rel": "More information on the graph limits setting",
393
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#graph-metadata"
394
+ }
395
+ ]
396
+ },
397
+ "graph_stacked_disaggregation": {
398
+ "type": "string",
399
+ "title": "Stacked disaggregation",
400
+ "description": "This can be used with the bar graph type to place a certain disaggregation into the same stacked bars.",
401
+ "links": [
402
+ {
403
+ "rel": "More information on the stacked disaggregation setting",
404
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#recommended-special-fields"
405
+ }
406
+ ]
407
+ },
408
+ "graph_title": {
409
+ "type": "string",
410
+ "title": "Graph title",
411
+ "description": "The title that displays above the graph/chart.",
412
+ "links": [
413
+ {
414
+ "rel": "More information on the graph title setting",
415
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-for-statistical-indicators"
416
+ }
417
+ ]
418
+ },
419
+ "graph_titles": {
420
+ "options": {"collapsed": true},
421
+ "format": "table",
422
+ "type": "array",
423
+ "title": "Graph titles",
424
+ "description": "As an alternative to `graph_title`, this can be used to set specific titles for particular units and/or series.",
425
+ "items": {
426
+ "type": "object",
427
+ "title": "Graph title",
428
+ "properties": {
429
+ "title": {
430
+ "type": "string",
431
+ "minLength": 1,
432
+ "title": "Title",
433
+ "description": "The graph title."
434
+ },
435
+ "unit": {
436
+ "type": "string",
437
+ "title": "Unit",
438
+ "description": "The unit of measurement the title applies to."
439
+ },
440
+ "series": {
441
+ "type": "string",
442
+ "title": "Series",
443
+ "description": "The series the title applies to."
444
+ }
445
+ }
446
+ }
447
+ },
448
+ "graph_type": {
449
+ "type": "string",
450
+ "title": "Graph type",
451
+ "description": "What type of graph to use for the indicator.",
452
+ "enum": ["line", "bar", "binary"],
453
+ "links": [
454
+ {
455
+ "rel": "More information on the graph titles setting",
456
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-for-statistical-indicators"
457
+ }
458
+ ]
459
+ },
460
+ "indicator_name": {
461
+ "type": "string",
462
+ "title": "Indicator name",
463
+ "description": "The name for the indicator, which displays at the top of the indicator page.",
464
+ "links": [
465
+ {
466
+ "rel": "More information on the indicator name setting",
467
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-fields"
468
+ }
469
+ ]
470
+ },
471
+ "indicator_number": {
472
+ "type": "string",
473
+ "title": "Indicator number",
474
+ "description": "The number (or 'id') for the indicator.",
475
+ "links": [
476
+ {
477
+ "rel": "More information on the indicator number setting",
478
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-fields"
479
+ }
480
+ ]
481
+ },
482
+ "national_geographical_coverage": {
483
+ "type": "string",
484
+ "title": "National geographical coverage",
485
+ "description": "A label used in the absence of any disaggregation.",
486
+ "links": [
487
+ {
488
+ "rel": "More information on the geographical coverage setting",
489
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-for-statistical-indicators"
490
+ }
491
+ ]
492
+ },
493
+ "page_content": {
494
+ "type": "string",
495
+ "format": "markdown",
496
+ "title": "Page content",
497
+ "description": "Content which displays in the main content area of the indicator page."
498
+ },
499
+ "reporting_status": {
500
+ "type": "string",
501
+ "title": "Reporting status",
502
+ "enum": ["complete", "inprogress", "notstarted", "notapplicable"],
503
+ "description": "The status of the indicator.",
504
+ "links": [
505
+ {
506
+ "rel": "More information on the reporting status setting",
507
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#mandatory-fields"
508
+ }
509
+ ]
510
+ },
511
+ "tags": {
512
+ "options": {"collapsed": true},
513
+ "format": "table",
514
+ "type": "array",
515
+ "title": "Tags",
516
+ "description": "An optional list of 'tags' to display under an indicator when it is listed on its goal page.",
517
+ "items": {
518
+ "type": "string",
519
+ "title": "Tag"
520
+ },
521
+ "links": [
522
+ {
523
+ "rel": "More information on the tags setting",
524
+ "href": "https://open-sdg.readthedocs.io/en/latest/metadata-format/#recommended-special-fields"
525
+ }
526
+ ]
527
+ }
528
+ },
529
+ "additionalProperties": true
530
+ }