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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }