ixbrl-viewer 1.4.1__py3-none-any.whl → 1.4.86__py3-none-any.whl

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.
Files changed (190) hide show
  1. iXBRLViewerPlugin/__init__.py +231 -127
  2. iXBRLViewerPlugin/_version.py +33 -3
  3. iXBRLViewerPlugin/constants.py +96 -2
  4. iXBRLViewerPlugin/featureConfig.py +8 -1
  5. iXBRLViewerPlugin/iXBRLViewer.py +356 -214
  6. iXBRLViewerPlugin/plugin.py +12 -0
  7. iXBRLViewerPlugin/ui.py +81 -50
  8. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  9. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +12 -5
  10. iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
  11. iXBRLViewerPlugin/viewer/src/data/utr.json +1244 -0
  12. iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
  13. iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
  14. iXBRLViewerPlugin/viewer/src/html/footnote-details.html +2 -2
  15. iXBRLViewerPlugin/viewer/src/html/inspector.html +352 -197
  16. iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
  17. iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
  18. iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
  19. iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
  20. iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
  21. iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
  22. iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
  23. iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
  24. iXBRLViewerPlugin/viewer/src/i18n/da/balancetypes.json +4 -0
  25. iXBRLViewerPlugin/viewer/src/i18n/da/currencies.json +13 -0
  26. iXBRLViewerPlugin/viewer/src/i18n/da/datatypes.json +9 -0
  27. iXBRLViewerPlugin/viewer/src/i18n/da/labelroles.json +24 -0
  28. iXBRLViewerPlugin/viewer/src/i18n/da/referenceparts.json +10 -0
  29. iXBRLViewerPlugin/viewer/src/i18n/da/scale.json +15 -0
  30. iXBRLViewerPlugin/viewer/src/i18n/da/tooltips.json +17 -0
  31. iXBRLViewerPlugin/viewer/src/i18n/da/translation.json +179 -0
  32. iXBRLViewerPlugin/viewer/src/i18n/de/balancetypes.json +4 -0
  33. iXBRLViewerPlugin/viewer/src/i18n/de/currencies.json +13 -0
  34. iXBRLViewerPlugin/viewer/src/i18n/de/datatypes.json +9 -0
  35. iXBRLViewerPlugin/viewer/src/i18n/de/labelroles.json +24 -0
  36. iXBRLViewerPlugin/viewer/src/i18n/de/referenceparts.json +10 -0
  37. iXBRLViewerPlugin/viewer/src/i18n/de/scale.json +15 -0
  38. iXBRLViewerPlugin/viewer/src/i18n/de/tooltips.json +17 -0
  39. iXBRLViewerPlugin/viewer/src/i18n/de/translation.json +179 -0
  40. iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
  41. iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
  42. iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
  43. iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
  44. iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
  45. iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +73 -23
  46. iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
  47. iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
  48. iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
  49. iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
  50. iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
  51. iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +87 -37
  52. iXBRLViewerPlugin/viewer/src/i18n/fr/balancetypes.json +4 -0
  53. iXBRLViewerPlugin/viewer/src/i18n/fr/currencies.json +13 -0
  54. iXBRLViewerPlugin/viewer/src/i18n/fr/datatypes.json +9 -0
  55. iXBRLViewerPlugin/viewer/src/i18n/fr/labelroles.json +24 -0
  56. iXBRLViewerPlugin/viewer/src/i18n/fr/referenceparts.json +10 -0
  57. iXBRLViewerPlugin/viewer/src/i18n/fr/scale.json +15 -0
  58. iXBRLViewerPlugin/viewer/src/i18n/fr/tooltips.json +17 -0
  59. iXBRLViewerPlugin/viewer/src/i18n/fr/translation.json +179 -0
  60. iXBRLViewerPlugin/viewer/src/i18n/nl/balancetypes.json +4 -0
  61. iXBRLViewerPlugin/viewer/src/i18n/nl/currencies.json +13 -0
  62. iXBRLViewerPlugin/viewer/src/i18n/nl/datatypes.json +9 -0
  63. iXBRLViewerPlugin/viewer/src/i18n/nl/labelroles.json +24 -0
  64. iXBRLViewerPlugin/viewer/src/i18n/nl/referenceparts.json +10 -0
  65. iXBRLViewerPlugin/viewer/src/i18n/nl/scale.json +15 -0
  66. iXBRLViewerPlugin/viewer/src/i18n/nl/tooltips.json +17 -0
  67. iXBRLViewerPlugin/viewer/src/i18n/nl/translation.json +179 -0
  68. iXBRLViewerPlugin/viewer/src/i18n/uk/balancetypes.json +4 -0
  69. iXBRLViewerPlugin/viewer/src/i18n/uk/currencies.json +13 -0
  70. iXBRLViewerPlugin/viewer/src/i18n/uk/datatypes.json +9 -0
  71. iXBRLViewerPlugin/viewer/src/i18n/uk/labelroles.json +24 -0
  72. iXBRLViewerPlugin/viewer/src/i18n/uk/referenceparts.json +10 -0
  73. iXBRLViewerPlugin/viewer/src/i18n/uk/scale.json +15 -0
  74. iXBRLViewerPlugin/viewer/src/i18n/uk/tooltips.json +17 -0
  75. iXBRLViewerPlugin/viewer/src/i18n/uk/translation.json +179 -0
  76. iXBRLViewerPlugin/viewer/src/icons/calculator.svg +13 -0
  77. iXBRLViewerPlugin/viewer/src/icons/circle-cross.svg +11 -0
  78. iXBRLViewerPlugin/viewer/src/icons/circle-tick.svg +11 -0
  79. iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
  80. iXBRLViewerPlugin/viewer/src/icons/dimension.svg +1 -5
  81. iXBRLViewerPlugin/viewer/src/icons/member.svg +2 -5
  82. iXBRLViewerPlugin/viewer/src/icons/multi-tag.svg +10 -0
  83. iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
  84. iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
  85. iXBRLViewerPlugin/viewer/src/js/accordian.js +5 -4
  86. iXBRLViewerPlugin/viewer/src/js/aspect.js +29 -10
  87. iXBRLViewerPlugin/viewer/src/js/aspect.test.js +40 -31
  88. iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
  89. iXBRLViewerPlugin/viewer/src/js/calculation.js +213 -0
  90. iXBRLViewerPlugin/viewer/src/js/calculation.test.js +306 -0
  91. iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +187 -0
  92. iXBRLViewerPlugin/viewer/src/js/chart.js +26 -24
  93. iXBRLViewerPlugin/viewer/src/js/chart.test.js +10 -9
  94. iXBRLViewerPlugin/viewer/src/js/concept.js +37 -4
  95. iXBRLViewerPlugin/viewer/src/js/concept.test.js +30 -6
  96. iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
  97. iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
  98. iXBRLViewerPlugin/viewer/src/js/dialog.js +6 -4
  99. iXBRLViewerPlugin/viewer/src/js/docOrderIndex.js +7 -7
  100. iXBRLViewerPlugin/viewer/src/js/fact.js +156 -59
  101. iXBRLViewerPlugin/viewer/src/js/fact.test.js +160 -29
  102. iXBRLViewerPlugin/viewer/src/js/factset.js +64 -15
  103. iXBRLViewerPlugin/viewer/src/js/factset.test.js +102 -31
  104. iXBRLViewerPlugin/viewer/src/js/footnote.js +8 -2
  105. iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
  106. iXBRLViewerPlugin/viewer/src/js/inspector.js +747 -221
  107. iXBRLViewerPlugin/viewer/src/js/inspector.test.js +143 -25
  108. iXBRLViewerPlugin/viewer/src/js/interval.js +70 -0
  109. iXBRLViewerPlugin/viewer/src/js/interval.test.js +153 -0
  110. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +391 -262
  111. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +134 -20
  112. iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
  113. iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
  114. iXBRLViewerPlugin/viewer/src/js/number-matcher.js +7 -3
  115. iXBRLViewerPlugin/viewer/src/js/number-matcher.test.js +4 -0
  116. iXBRLViewerPlugin/viewer/src/js/outline.js +34 -13
  117. iXBRLViewerPlugin/viewer/src/js/outline.test.js +97 -91
  118. iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
  119. iXBRLViewerPlugin/viewer/src/js/report.js +260 -351
  120. iXBRLViewerPlugin/viewer/src/js/report.test.js +95 -27
  121. iXBRLViewerPlugin/viewer/src/js/reportset.js +264 -0
  122. iXBRLViewerPlugin/viewer/src/js/reportset.test.js +357 -0
  123. iXBRLViewerPlugin/viewer/src/js/search.js +72 -38
  124. iXBRLViewerPlugin/viewer/src/js/search.test.js +184 -84
  125. iXBRLViewerPlugin/viewer/src/js/summary.js +34 -8
  126. iXBRLViewerPlugin/viewer/src/js/summary.test.js +69 -25
  127. iXBRLViewerPlugin/viewer/src/js/tableExport.js +9 -9
  128. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
  129. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
  130. iXBRLViewerPlugin/viewer/src/js/test-utils.js +46 -0
  131. iXBRLViewerPlugin/viewer/src/js/theme.js +50 -0
  132. iXBRLViewerPlugin/viewer/src/js/unit.js +90 -32
  133. iXBRLViewerPlugin/viewer/src/js/unit.test.js +62 -25
  134. iXBRLViewerPlugin/viewer/src/js/util.js +94 -0
  135. iXBRLViewerPlugin/viewer/src/js/util.test.js +33 -1
  136. iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
  137. iXBRLViewerPlugin/viewer/src/js/viewer.js +205 -181
  138. iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
  139. iXBRLViewerPlugin/viewer/src/less/accordian.less +10 -6
  140. iXBRLViewerPlugin/viewer/src/less/block-list.less +16 -5
  141. iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +83 -0
  142. iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
  143. iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
  144. iXBRLViewerPlugin/viewer/src/less/colours.less +32 -20
  145. iXBRLViewerPlugin/viewer/src/less/common.less +3 -3
  146. iXBRLViewerPlugin/viewer/src/less/components.less +6 -4
  147. iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
  148. iXBRLViewerPlugin/viewer/src/less/dialog.less +21 -14
  149. iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
  150. iXBRLViewerPlugin/viewer/src/less/inspector.less +1045 -726
  151. iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
  152. iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
  153. iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
  154. iXBRLViewerPlugin/viewer/src/less/tabs.less +9 -9
  155. iXBRLViewerPlugin/viewer/src/less/text-block-viewer.less +2 -0
  156. iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
  157. iXBRLViewerPlugin/viewer/src/less/validation-report.less +2 -3
  158. iXBRLViewerPlugin/viewer/src/less/viewer.less +105 -74
  159. iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
  160. iXBRLViewerPlugin/xhtmlserialize.py +59 -45
  161. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/METADATA +181 -50
  162. ixbrl_viewer-1.4.86.dist-info/RECORD +217 -0
  163. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/WHEEL +1 -1
  164. ixbrl_viewer-1.4.1.dist-info/LICENSE → ixbrl_viewer-1.4.86.dist-info/licenses/LICENSE.md +8 -14
  165. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/top_level.txt +0 -1
  166. iXBRLViewerPlugin/viewer/src/js/calculations.js +0 -111
  167. iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
  168. ixbrl_viewer-1.4.1.dist-info/RECORD +0 -155
  169. tests/__init__.py +0 -0
  170. tests/puppeteer/framework/core_elements.js +0 -117
  171. tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
  172. tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -80
  173. tests/puppeteer/framework/page_objects/search_panel.js +0 -76
  174. tests/puppeteer/framework/page_objects/toolbar.js +0 -18
  175. tests/puppeteer/framework/utils.js +0 -3
  176. tests/puppeteer/framework/viewer_page.js +0 -103
  177. tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
  178. tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
  179. tests/puppeteer/test_filings/highlights.zip +0 -0
  180. tests/puppeteer/tests/fact_properties.test.js +0 -78
  181. tests/puppeteer/tests/highlight.test.js +0 -186
  182. tests/puppeteer/tests/search.test.js +0 -86
  183. tests/puppeteer/tools/generate.sh +0 -15
  184. tests/unit_tests/__init__.py +0 -0
  185. tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
  186. tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -39
  187. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -641
  188. tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
  189. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/entry_points.txt +0 -0
  190. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info/licenses}/NOTICE +0 -0
@@ -1,26 +1,54 @@
1
1
  # See COPYRIGHT.md for copyright information
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import argparse
6
+ import atexit
5
7
  import io
6
8
  import logging
7
9
  import os
10
+ import shutil
8
11
  import sys
9
12
  import tempfile
10
13
  import traceback
14
+ import webbrowser
11
15
  from optparse import OptionGroup, OptionParser
12
- from typing import Optional, Union
16
+ from pathlib import Path
17
+ from typing import TYPE_CHECKING, Any, cast
13
18
 
14
- from arelle import Cntlr
19
+ from arelle.Cntlr import Cntlr
15
20
  from arelle.LocalViewer import LocalViewer
16
21
  from arelle.ModelDocument import Type
17
- from arelle.webserver.bottle import static_file
18
-
19
- from .constants import CONFIG_FEATURE_PREFIX, CONFIG_LAUNCH_ON_LOAD, \
20
- CONFIG_SCRIPT_URL, DEFAULT_LAUNCH_ON_LOAD, DEFAULT_OUTPUT_NAME, \
21
- DEFAULT_VIEWER_PATH, FEATURE_CONFIGS
22
- from .iXBRLViewer import IXBRLViewerBuilder, IXBRLViewerBuilderError
23
-
22
+ from arelle.ModelXbrl import ModelXbrl
23
+ from arelle.typing import TypeGetText
24
+ from arelle.UrlUtil import isHttpUrl
25
+ from bottle import static_file # type: ignore[import-untyped]
26
+
27
+ if TYPE_CHECKING:
28
+ from tkinter import Menu
29
+
30
+ from arelle.CntlrWinMain import CntlrWinMain
31
+
32
+ from .constants import (
33
+ CONFIG_COPY_SCRIPT,
34
+ CONFIG_FEATURE_PREFIX,
35
+ CONFIG_LAUNCH_ON_LOAD,
36
+ CONFIG_SCRIPT_URL,
37
+ DEFAULT_COPY_SCRIPT,
38
+ DEFAULT_JS_FILENAME,
39
+ DEFAULT_LAUNCH_ON_LOAD,
40
+ DEFAULT_OUTPUT_NAME,
41
+ DEFAULT_VIEWER_PATH,
42
+ ERROR_MESSAGE_CODE,
43
+ EXCEPTION_MESSAGE_CODE,
44
+ FEATURE_CONFIGS,
45
+ )
46
+ from .iXBRLViewer import IXBRLViewerBuilder, IXBRLViewerBuilderError, isInlineDoc
47
+ from .plugin import IXBRLViewerPluginData
48
+
49
+ _: TypeGetText
50
+
51
+ PLUGIN_NAME = 'ixbrl-viewer'
24
52
 
25
53
  #
26
54
  # GUI operation:
@@ -46,7 +74,7 @@ from .iXBRLViewer import IXBRLViewerBuilder, IXBRLViewerBuilderError
46
74
  #
47
75
 
48
76
 
49
- def iXBRLViewerCommandLineOptionExtender(parser, *args, **kwargs):
77
+ def iXBRLViewerCommandLineOptionExtender(parser: OptionParser, *args: Any, **kwargs: Any) -> None:
50
78
  parser.add_option("--save-viewer",
51
79
  action="store",
52
80
  dest="saveViewerDest",
@@ -55,7 +83,18 @@ def iXBRLViewerCommandLineOptionExtender(parser, *args, **kwargs):
55
83
  action="store",
56
84
  dest="viewerURL",
57
85
  default=DEFAULT_VIEWER_PATH,
58
- help="Specify the URL to ixbrlviewer.js")
86
+ help="A filepath or URL to the iXBRL Viewer JavaScript file which will be downloaded or copied into the output directory."
87
+ " If a relative filepath is to be copied it will be resolved relative to the current working directory."
88
+ " If '--viewer-no-copy-script' is used, the '--viewer-url' file will not be copied or downloaded and instead directly referenced from the HTML file."
89
+ " Examples: 'customViewerScript.js', '/path/to/ixbrlviewer.js', 'https://example.com/ixbrlviewer.js'."
90
+ f" The default value is '{DEFAULT_JS_FILENAME}'.")
91
+ parser.add_option("--viewer-no-copy-script",
92
+ action="store_true",
93
+ dest="viewerNoCopyScript",
94
+ default=False,
95
+ help="Prevent copying the iXBRL Viewer's JavaScript file from '--viewer-url' into the output directory."
96
+ " If used, the iXBRL Viewer HTML file will reference the '--viewer-url' directly."
97
+ " It must be a valid script location at the time the viewer is opened in a browser.")
59
98
  parser.add_option("--viewer-validation-messages",
60
99
  dest="validationMessages",
61
100
  action="store_true",
@@ -81,136 +120,189 @@ def iXBRLViewerCommandLineOptionExtender(parser, *args, **kwargs):
81
120
  default=False,
82
121
  dest="zipViewerOutput",
83
122
  help="Converts the viewer output into a self contained zip")
123
+
84
124
  featureGroup = OptionGroup(parser, "Viewer Features",
85
125
  "See viewer README for information on enabling/disabling features.")
86
126
  for featureConfig in FEATURE_CONFIGS:
87
- arg = f'--viewer-feature-{featureConfig.key}'
88
- featureGroup.add_option(arg, arg.lower(), action="store_true", default=False, help=featureConfig.description)
127
+ arg = f'--viewer-feature-{featureConfig.key}'.replace('_', '-')
128
+ featureGroup.add_option(
129
+ arg,
130
+ arg.lower(),
131
+ action=featureConfig.cliAction,
132
+ default=featureConfig.cliDefault,
133
+ help=featureConfig.description
134
+ )
89
135
  parser.add_option_group(featureGroup)
90
136
 
137
+ def pluginData(cntlr: Cntlr) -> IXBRLViewerPluginData:
138
+ pd = cast(IXBRLViewerPluginData | None, cntlr.getPluginData(PLUGIN_NAME))
139
+ if pd is None:
140
+ pd = IXBRLViewerPluginData(PLUGIN_NAME)
141
+ cntlr.setPluginData(pd)
142
+ return pd
143
+
144
+ def resetPluginData(cntlr: Cntlr) -> None:
145
+ pluginData(cntlr).builder = None
146
+
147
+ def processModel(cntlr: Cntlr, modelXbrl: ModelXbrl) -> None:
148
+ try:
149
+ if isInlineDoc(modelXbrl.modelDocument):
150
+ builder = pluginData(cntlr).builder
151
+ assert builder is not None, "iXBRL Viewer builder must be initialized before processing model"
152
+ builder.processModel(modelXbrl)
153
+ except IXBRLViewerBuilderError as ex:
154
+ print(ex)
155
+ except Exception as ex:
156
+ tb = traceback.format_tb(sys.exc_info()[2])
157
+ cntlr.addToLog(
158
+ "Exception %(ex)s\nTraceback %(traceback)s",
159
+ messageCode=EXCEPTION_MESSAGE_CODE,
160
+ level=logging.ERROR,
161
+ messageArgs={
162
+ 'ex': ex,
163
+ 'traceback': tb,
164
+ },
165
+ )
91
166
 
92
167
  def generateViewer(
93
168
  cntlr: Cntlr,
94
- saveViewerDest: Union[io.BytesIO, str],
95
- viewerURL: str = DEFAULT_VIEWER_PATH,
169
+ saveViewerDest: io.BytesIO | str | None,
170
+ viewerURL: str | None = None,
96
171
  showValidationMessages: bool = False,
97
- useStubViewer: bool = False,
98
172
  zipViewerOutput: bool = False,
99
- features: Optional[list[str]] = None,
100
- packageDownloadURL: str = None):
173
+ packageDownloadURL: str | None = None,
174
+ copyScript: bool = True,
175
+ ) -> None:
101
176
  """
102
- Generate and save a viewer at the given destination (file, directory, or in-memory file) with the given viewer URL.
103
- If the viewer URL is a location on the local file system, a copy will be placed included in the output destination.
177
+ Generate and save an iXBRL viewer at the given destination (file, directory, or in-memory file) with the given viewer script URL.
178
+ If copyScript is True the viewer script will be copied into the output destination.
104
179
  :param cntlr: The arelle controller that contains the model to be included in the viewer
105
180
  :param saveViewerDest: The target that viewer data/files will be written to (path to file or directory, or a file object itself).
106
- :param viewerURL: The filepath or URL location of the viewer script.
181
+ :param viewerURL: The filepath or URL location of the iXBRL Viewer JavaScript file.
107
182
  :param showValidationMessages: True if validation messages should be shown in the viewer.
108
183
  :param useStubViewer: True if the stub viewer should be used.
109
184
  :param zipViewerOutput: True if the destination is a zip archive.
110
- :param features: List of feature names to enable via generated JSON data.
185
+ :param packageDownloadURL: Optional URL to use as the report package download URL.
186
+ :param copyScript: Controls if the script referenced by viewerURL is copied into the output directory, or directly set as the 'src' value of the script tag in the HTML iXBRL Viewer.
111
187
  """
112
188
  # extend XBRL-loaded run processing for this option
113
- if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None or not cntlr.modelManager.modelXbrl.modelDocument:
114
- cntlr.addToLog("No taxonomy loaded.")
189
+ abortGenerationMsg = "Skipping iXBRL Viewer generation."
190
+ if not saveViewerDest:
191
+ cntlr.addToLog(f"iXBRL Viewer destination not provided. {abortGenerationMsg}", messageCode=EXCEPTION_MESSAGE_CODE)
115
192
  return
116
- modelXbrl = cntlr.modelManager.modelXbrl
117
- if modelXbrl.modelDocument.type not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET):
118
- cntlr.addToLog("No inline XBRL document loaded.")
193
+
194
+ viewerURL = viewerURL or DEFAULT_VIEWER_PATH
195
+
196
+ bldr = pluginData(cntlr).builder
197
+ assert bldr is not None, "iXBRL Viewer builder must be initialized before generating viewer"
198
+
199
+ if bldr.reportCount == 0:
200
+ cntlr.addToLog(f"No inline XBRL documents loaded. {abortGenerationMsg}", messageCode=ERROR_MESSAGE_CODE)
119
201
  return
202
+
120
203
  copyScriptPath = None
121
- if isinstance(saveViewerDest, str):
122
- # Note on URLs: Rather than rely on logic to determine if the input is a file
123
- # path or web address, we can allow web addresses to be considered relative paths.
124
- # Unless the URL happens to resolve to an existing file on the local filesystem,
125
- # it will skip this step and pass through into the viewer as expected.
126
- if os.path.isabs(viewerURL):
127
- viewerAbsolutePath = viewerURL
128
- else:
129
- viewerAbsolutePath = getAbsoluteViewerPath(saveViewerDest, viewerURL)
130
-
131
- if os.path.isfile(viewerAbsolutePath):
132
- # The script was found on the local file system and will be copied into the
133
- # destination directory, so the local path (just the basename) of viewerURL should
134
- # be passed to the script tag
135
- copyScriptPath = viewerURL
136
- viewerURL = os.path.basename(viewerURL)
204
+ if copyScript:
205
+ originalViewerURL = viewerURL
206
+ viewerPath = None
207
+ if isHttpUrl(originalViewerURL):
208
+ cacheScript = cntlr.webCache.getfilename(originalViewerURL)
209
+ if cacheScript and (cacheScriptPath := Path(cacheScript)).is_file():
210
+ viewerPath = cacheScriptPath
211
+ else:
212
+ downloadFailedErrorMessage = f"Unable to download iXBRL Viewer script '{originalViewerURL}'."
213
+ if cntlr.webCache.workOffline:
214
+ downloadFailedErrorMessage += " Disable offline mode and try again."
215
+ cntlr.addToLog(f"{downloadFailedErrorMessage} {abortGenerationMsg}", messageCode=EXCEPTION_MESSAGE_CODE)
216
+ return
217
+
218
+ if not viewerPath:
219
+ viewerPath = Path(viewerURL)
220
+ copyScriptPath = viewerPath.resolve()
221
+ viewerURL = viewerPath.name
222
+ if not viewerPath.is_file():
223
+ cntlr.addToLog(f"iXBRL Viewer script not found at '{viewerPath}'. {abortGenerationMsg}", messageCode=EXCEPTION_MESSAGE_CODE)
224
+ return
225
+
137
226
  try:
138
- out = saveViewerDest
139
- if out:
140
- viewerBuilder = IXBRLViewerBuilder(modelXbrl)
141
- if features:
142
- for feature in features:
143
- viewerBuilder.enableFeature(feature)
144
- iv = viewerBuilder.createViewer(scriptUrl=viewerURL, showValidations=showValidationMessages, useStubViewer=useStubViewer, packageDownloadURL=packageDownloadURL)
145
- if iv is not None:
146
- iv.save(out, zipOutput=zipViewerOutput, copyScriptPath=copyScriptPath)
227
+ iv = bldr.createViewer(scriptUrl=viewerURL, showValidations=showValidationMessages, packageDownloadURL=packageDownloadURL)
228
+ if iv is not None:
229
+ iv.save(saveViewerDest, zipOutput=zipViewerOutput, copyScriptPath=copyScriptPath)
147
230
  except IXBRLViewerBuilderError as ex:
148
- print(ex.message)
231
+ print(ex)
149
232
  except Exception as ex:
150
- cntlr.addToLog("Exception {} \nTraceback {}".format(ex, traceback.format_tb(sys.exc_info()[2])))
233
+ tb = traceback.format_tb(sys.exc_info()[2])
234
+ cntlr.addToLog(f"Exception {ex} \nTraceback {tb}", messageCode=EXCEPTION_MESSAGE_CODE)
235
+ resetPluginData(cntlr)
151
236
 
152
237
 
153
- def getAbsoluteViewerPath(saveViewerPath: str, relativeViewerPath: str) -> str:
154
- """
155
- Generate a path to the viewer script given the save destination path as a starting point.
156
- :param saveViewerPath: Path to file or directory where viewer output will be saved.
157
- :param relativeViewerPath: Path to save destination relative to viewer save path.
158
- :return: An absolute file path to the viewer.
159
- """
160
- saveViewerDir = saveViewerPath
161
- if os.path.isfile(saveViewerDir):
162
- saveViewerDir = os.path.dirname(os.path.join(os.getcwd(), saveViewerDir))
163
- return os.path.join(saveViewerDir, relativeViewerPath)
164
-
165
-
166
- def getFeaturesFromOptions(options: Union[argparse.Namespace, OptionParser]):
167
- return [
168
- featureConfig.key
169
- for featureConfig in FEATURE_CONFIGS
170
- if getattr(options, f'viewer_feature_{featureConfig.key}') or getattr(options, f'viewer_feature_{featureConfig.key.lower()}')
171
- ]
238
+ def getFeaturesFromOptions(options: argparse.Namespace | OptionParser) -> dict[str, Any]:
239
+ features = {}
240
+ for featureConfig in FEATURE_CONFIGS:
241
+ key = featureConfig.key
242
+ option = f'viewer_feature_{key}'
243
+ value = getattr(options, option, None)
244
+ if value is not None:
245
+ features[key] = value
246
+ return features
172
247
 
173
248
 
174
- def iXBRLViewerCommandLineXbrlRun(cntlr, options, *args, **kwargs):
249
+ def iXBRLViewerCommandLineXbrlRun(
250
+ cntlr: Cntlr,
251
+ options: argparse.Namespace,
252
+ modelXbrl: ModelXbrl,
253
+ *args: Any,
254
+ **kwargs: Any,
255
+ ) -> None:
256
+ pd = pluginData(cntlr)
257
+ if pd.builder is None:
258
+ pd.builder = IXBRLViewerBuilder(cntlr, useStubViewer = options.useStubViewer, features=getFeaturesFromOptions(options))
259
+ processModel(cntlr, modelXbrl)
260
+
261
+ def iXBRLViewerCommandLineFilingEnd(cntlr: Cntlr, options: argparse.Namespace, *args: Any, **kwargs: Any) -> None:
175
262
  generateViewer(
176
- cntlr,
177
- options.saveViewerDest or kwargs.get("responseZipStream"),
178
- options.viewerURL,
179
- options.validationMessages,
180
- options.useStubViewer,
181
- options.zipViewerOutput,
182
- getFeaturesFromOptions(options),
183
- options.packageDownloadURL,
263
+ cntlr=cntlr,
264
+ saveViewerDest=options.saveViewerDest or kwargs.get("responseZipStream"),
265
+ viewerURL=options.viewerURL,
266
+ copyScript=not options.viewerNoCopyScript,
267
+ showValidationMessages=options.validationMessages,
268
+ zipViewerOutput=options.zipViewerOutput,
269
+ packageDownloadURL=options.packageDownloadURL,
184
270
  )
185
271
 
186
272
 
187
- def iXBRLViewerSaveCommand(cntlr):
273
+ def iXBRLViewerSaveCommand(cntlr: CntlrWinMain) -> None:
188
274
  from .ui import SaveViewerDialog
189
275
  if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None:
190
- cntlr.addToLog("No document loaded.")
276
+ cntlr.addToLog("No document loaded.", messageCode=ERROR_MESSAGE_CODE) # type: ignore[no-untyped-call]
191
277
  return
192
278
  modelXbrl = cntlr.modelManager.modelXbrl
193
- if modelXbrl.modelDocument.type not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET):
194
- cntlr.addToLog("No inline XBRL document loaded.")
279
+ if modelXbrl.modelDocument is None or modelXbrl.modelDocument.type not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET):
280
+ cntlr.addToLog("No inline XBRL document loaded.", messageCode=ERROR_MESSAGE_CODE) # type: ignore[no-untyped-call]
195
281
  return
196
282
  dialog = SaveViewerDialog(cntlr)
197
283
  dialog.render()
284
+ features = {
285
+ feature: True
286
+ for feature in dialog.features()
287
+ }
288
+ pluginData(cntlr).builder = IXBRLViewerBuilder(cntlr, features=features)
289
+ processModel(cntlr, modelXbrl)
198
290
  if dialog.accepted and dialog.filename():
199
291
  generateViewer(
200
- cntlr,
201
- dialog.filename(),
202
- dialog.scriptUrl(),
292
+ cntlr=cntlr,
293
+ saveViewerDest=dialog.filename(),
294
+ viewerURL=dialog.scriptUrl(),
295
+ copyScript=dialog.copyScript(),
203
296
  zipViewerOutput=dialog.zipViewerOutput(),
204
- features=dialog.features()
205
297
  )
206
298
 
207
299
 
208
- def iXBRLViewerSettingsCommand(cntlr):
300
+ def iXBRLViewerSettingsCommand(cntlr: CntlrWinMain) -> None:
209
301
  from .ui import SettingsDialog
210
302
  SettingsDialog(cntlr).render()
211
303
 
212
304
 
213
- def iXBRLViewerToolsMenuExtender(cntlr, menu, *args, **kwargs):
305
+ def iXBRLViewerToolsMenuExtender(cntlr: CntlrWinMain, menu: Menu, *args: Any, **kwargs: Any) -> None:
214
306
  # Add Tools menu
215
307
  from tkinter import Menu # must only import if GUI present (no tkinter on GUI-less servers)
216
308
  viewerMenu = Menu(cntlr.menubar, tearoff=0)
@@ -227,79 +319,90 @@ def iXBRLViewerToolsMenuExtender(cntlr, menu, *args, **kwargs):
227
319
  command=lambda: iXBRLViewerSaveCommand(cntlr))
228
320
 
229
321
 
230
- def toolsMenuExtender(cntlr, menu, *args, **kwargs):
322
+ def toolsMenuExtender(cntlr: CntlrWinMain, menu: Menu, *args: Any, **kwargs: Any) -> None:
231
323
  iXBRLViewerToolsMenuExtender(cntlr, menu, *args, **kwargs)
232
324
 
233
325
 
234
- def commandLineOptionExtender(*args, **kwargs):
326
+ def commandLineOptionExtender(*args: Any, **kwargs: Any) -> None:
235
327
  iXBRLViewerCommandLineOptionExtender(*args, **kwargs)
236
328
 
237
329
 
238
- def commandLineRun(*args, **kwargs):
239
- iXBRLViewerCommandLineXbrlRun(*args, **kwargs)
330
+ def commandLineRun(cntlr: Cntlr, options: argparse.Namespace, modelXbrl: ModelXbrl, *args: Any, **kwargs: Any) -> None:
331
+ iXBRLViewerCommandLineXbrlRun(cntlr, options, modelXbrl, *args, **kwargs)
240
332
 
333
+ def commandLineFilingEnd(*args: Any, **kwargs: Any) -> None:
334
+ iXBRLViewerCommandLineFilingEnd(*args, **kwargs)
241
335
 
242
336
  class iXBRLViewerLocalViewer(LocalViewer):
243
337
  # plugin-specific local file handler
244
- def getLocalFile(self, file, relpath, request):
245
- _report, _sep, _file = file.partition("/")
246
- if file == 'ixbrlviewer.js':
247
- return static_file('ixbrlviewer.js', os.path.dirname(DEFAULT_VIEWER_PATH))
248
- elif _report.isnumeric(): # in reportsFolder folder
338
+ def getLocalFile(self, file: str, relpath: str, request: Any) -> Any:
339
+ if file == DEFAULT_JS_FILENAME:
340
+ return static_file(DEFAULT_JS_FILENAME, os.path.dirname(DEFAULT_VIEWER_PATH))
341
+ _report, _, _file = file.partition("/")
342
+ if _report.isnumeric(): # in reportsFolder folder
249
343
  # check if file is in the current or parent directory
250
344
  _fileDir = self.reportsFolders[int(_report)]
251
345
  _fileExists = False
252
346
  if os.path.exists(os.path.join(_fileDir, _file)):
253
347
  _fileExists = True
254
- elif "/" in _file and os.path.exists(os.path.join(_fileDir, os.path.filepart(_file))):
348
+ elif "/" in _file and os.path.exists(os.path.join(_fileDir, os.path.basename(_file))):
255
349
  # xhtml in a subdirectory for output files may refer to an image file in parent directory
256
350
  _fileExists = True
257
- _file = os.path.filepart(_file)
258
- if not _fileExists:
259
- self.cntlr.addToLog("http://localhost:{}/{}".format(self.port, file), messageCode="localViewer:fileNotFound", level=logging.DEBUG)
351
+ _file = os.path.basename(_file)
352
+ if not _fileExists and self.cntlr is not None:
353
+ self.cntlr.addToLog(
354
+ f"http://localhost:{self.port}/{file}",
355
+ messageCode="localViewer:fileNotFound",
356
+ level=logging.DEBUG,
357
+ )
260
358
  return static_file(_file, root=_fileDir, headers=self.noCacheHeaders) # extra_headers modification to py-bottle
261
- return static_file(file, root="/") # probably can't get here unless path is wrong
359
+ return static_file(file, root="/") # absolute path used for ixbrlviewer.js.
262
360
 
263
361
 
264
- def guiRun(cntlr, modelXbrl, attach, *args, **kwargs):
362
+ def guiRun(cntlr: CntlrWinMain, modelXbrl: ModelXbrl, attach: Any, *args: Any, **kwargs: Any) -> None:
265
363
  """ run iXBRL Viewer using GUI interactions for a single instance or testcases """
364
+ if cntlr.config is None:
365
+ return
266
366
  if not cntlr.config.setdefault(CONFIG_LAUNCH_ON_LOAD, DEFAULT_LAUNCH_ON_LOAD):
267
367
  # Don't run on launch if the option has been disabled
268
368
  return
269
369
  try:
270
- import webbrowser
271
- global tempViewer
272
- tempViewer = tempfile.TemporaryDirectory()
370
+ tempViewerDir = tempfile.mkdtemp()
371
+ atexit.register(shutil.rmtree, tempViewerDir, ignore_errors=True)
273
372
  viewer_file_name = DEFAULT_OUTPUT_NAME
274
- features = [
275
- c.key
276
- for c in FEATURE_CONFIGS
277
- if cntlr.config.setdefault(f'{CONFIG_FEATURE_PREFIX}{c.key}', False)
278
- ]
373
+ features: dict[str, bool] = {}
374
+ for featureConfig in FEATURE_CONFIGS:
375
+ if cntlr.config.setdefault(f'{CONFIG_FEATURE_PREFIX}{featureConfig.key}', False):
376
+ features[featureConfig.key] = True
377
+ pluginData(cntlr).builder = IXBRLViewerBuilder(cntlr, useStubViewer=True, features=features)
378
+ processModel(cntlr, modelXbrl)
279
379
  generateViewer(
280
- cntlr,
281
- saveViewerDest=tempViewer.name,
282
- viewerURL=cntlr.config.setdefault(CONFIG_SCRIPT_URL, DEFAULT_VIEWER_PATH),
283
- useStubViewer=True,
284
- features=features
380
+ cntlr=cntlr,
381
+ saveViewerDest=tempViewerDir,
382
+ viewerURL=cntlr.config.get(CONFIG_SCRIPT_URL),
383
+ copyScript=cntlr.config.get(CONFIG_COPY_SCRIPT, DEFAULT_COPY_SCRIPT),
285
384
  )
286
- localViewer = iXBRLViewerLocalViewer("iXBRL Viewer", os.path.dirname(__file__))
287
- localhost = localViewer.init(cntlr, tempViewer.name)
288
- webbrowser.open(f'{localhost}/{viewer_file_name}')
385
+ if Path(tempViewerDir, viewer_file_name).exists():
386
+ localViewer = iXBRLViewerLocalViewer("iXBRL Viewer", os.path.dirname(__file__)) # type: ignore[no-untyped-call]
387
+ localhost = localViewer.init(cntlr, tempViewerDir) # type: ignore[no-untyped-call]
388
+ webbrowser.open(f'{localhost}/{viewer_file_name}')
289
389
  except Exception as ex:
290
390
  modelXbrl.error(
291
- "viewer:exception",
292
- "Exception %(exception)s \sTraceback %(traceback)s",
391
+ EXCEPTION_MESSAGE_CODE,
392
+ "Exception %(exception)s \nTraceback %(traceback)s",
293
393
  modelObject=modelXbrl, exception=ex, traceback=traceback.format_tb(sys.exc_info()[2])
294
394
  )
295
395
 
296
396
 
297
- def load_plugin_url():
397
+ def load_plugin_url() -> str:
298
398
  return __file__
299
399
 
300
400
 
301
401
  __pluginInfo__ = {
302
- 'name': 'ixbrl-viewer',
402
+ 'name': PLUGIN_NAME,
403
+ 'aliases': [
404
+ 'iXBRLViewerPlugin',
405
+ ],
303
406
  'version': '0.1',
304
407
  'description': "iXBRL Viewer creator",
305
408
  'license': 'License :: OSI Approved :: Apache License, Version 2.0 (Apache-2.0)',
@@ -307,6 +410,7 @@ __pluginInfo__ = {
307
410
  'copyright': 'Copyright :: Workiva Inc. :: 2019',
308
411
  'CntlrCmdLine.Options': commandLineOptionExtender,
309
412
  'CntlrCmdLine.Xbrl.Run': commandLineRun,
413
+ 'CntlrCmdLine.Filing.End': commandLineFilingEnd,
310
414
  'CntlrWinMain.Menu.Tools': toolsMenuExtender,
311
415
  'CntlrWinMain.Xbrl.Loaded': guiRun,
312
416
  }
@@ -1,4 +1,34 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
- __version__ = version = '1.4.1'
4
- __version_tuple__ = version_tuple = (1, 4, 1)
3
+
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
12
+
13
+ TYPE_CHECKING = False
14
+ if TYPE_CHECKING:
15
+ from typing import Tuple
16
+ from typing import Union
17
+
18
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
20
+ else:
21
+ VERSION_TUPLE = object
22
+ COMMIT_ID = object
23
+
24
+ version: str
25
+ __version__: str
26
+ __version_tuple__: VERSION_TUPLE
27
+ version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
30
+
31
+ __version__ = version = '1.4.86'
32
+ __version_tuple__ = version_tuple = (1, 4, 86)
33
+
34
+ __commit_id__ = commit_id = None
@@ -1,5 +1,7 @@
1
1
  # See COPYRIGHT.md for copyright information
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import os
4
6
 
5
7
  from .featureConfig import FeatureConfig
@@ -7,22 +9,114 @@ from .featureConfig import FeatureConfig
7
9
  CONFIG_FEATURE_PREFIX = 'iXBRLViewerFeature_'
8
10
  CONFIG_FILE_DIRECTORY = 'iXBRLViewerFileDir'
9
11
  CONFIG_LAUNCH_ON_LOAD = 'iXBRLViewerLaunchOnLoad'
12
+ CONFIG_COPY_SCRIPT = 'iXBRLViewerCopyScript'
10
13
  CONFIG_OUTPUT_FILE = 'iXBRLViewerOutputFile'
11
14
  CONFIG_SCRIPT_URL = 'iXBRLViewerScriptURL'
12
15
  CONFIG_ZIP_OUTPUT = 'iXBRLViewerZipOutput'
13
16
 
17
+ ERROR_MESSAGE_CODE = 'viewer:error'
18
+ EXCEPTION_MESSAGE_CODE = 'viewer:exception'
19
+ INFO_MESSAGE_CODE = 'viewer:info'
20
+
14
21
  DEFAULT_LAUNCH_ON_LOAD = True
22
+ DEFAULT_COPY_SCRIPT = True
15
23
  DEFAULT_OUTPUT_NAME = 'ixbrlviewer.html'
16
- DEFAULT_VIEWER_PATH = os.path.join(os.path.dirname(__file__), "viewer", "dist", "ixbrlviewer.js")
24
+ DEFAULT_JS_FILENAME = 'ixbrlviewer.js'
25
+ DEFAULT_VIEWER_PATH = os.path.join(os.path.dirname(__file__), "viewer", "dist", DEFAULT_JS_FILENAME)
17
26
 
18
27
  FEATURE_CONFIGS = [
28
+ FeatureConfig(
29
+ key='home_link_label',
30
+ label='Home Link (Label)',
31
+ description='Customizes the label of the "Home" link enabled by "home_link_url".',
32
+ cliAction='store',
33
+ cliDefault=None,
34
+ guiVisible=False,
35
+ guiDefault=None,
36
+ ),
37
+ FeatureConfig(
38
+ key='home_link_url',
39
+ label='Home Link (URL)',
40
+ description='Adds a "Home" link that directs to the specified URL. Label can be customized with "home_link_label".',
41
+ cliAction='store',
42
+ cliDefault=None,
43
+ guiVisible=False,
44
+ guiDefault=None,
45
+ ),
46
+ FeatureConfig(
47
+ key='support_link',
48
+ label='Support Link',
49
+ description='Adds a "Support" link that directs to the specified URL.',
50
+ cliAction='store',
51
+ cliDefault=None,
52
+ guiVisible=False,
53
+ guiDefault=None,
54
+ ),
55
+ FeatureConfig(
56
+ key='survey_link',
57
+ label='Survey Link',
58
+ description='Adds a "Survey" link that directs to the specified URL.',
59
+ cliAction='store',
60
+ cliDefault=None,
61
+ guiVisible=False,
62
+ guiDefault=None,
63
+ ),
19
64
  FeatureConfig(
20
65
  key='review',
21
66
  label='Review Mode',
22
67
  description='Enables highlighting of untagged numbers and dates.',
68
+ cliAction='store_true',
69
+ cliDefault=False,
70
+ guiVisible=True,
71
+ guiDefault=False
72
+ ),
73
+ FeatureConfig(
74
+ key='mandatory_facts',
75
+ label='Mandatory Facts',
76
+ description='Enables the display of mandatory facts for the selected taxonomy.',
77
+ cliAction='store',
78
+ cliDefault=None,
79
+ guiVisible=False,
80
+ guiDefault=None
81
+ ),
82
+ FeatureConfig(
83
+ key='search_on_startup',
84
+ label='Search on startup',
85
+ description='Show the search pane by default on startup.',
86
+ cliAction='store_true',
87
+ cliDefault=None,
88
+ guiVisible=True,
89
+ guiDefault=False
90
+ ),
91
+ FeatureConfig(
92
+ key='highlight_facts_on_startup',
93
+ label='Highlight facts on startup',
94
+ description='Default "Highlight all facts" to on.',
95
+ cliAction='store_true',
96
+ cliDefault=None,
23
97
  guiVisible=True,
24
98
  guiDefault=False
25
99
  )
26
100
  ]
27
-
28
101
  GUI_FEATURE_CONFIGS = [c for c in FEATURE_CONFIGS if c.guiVisible]
102
+
103
+ MANDATORY_FACTS = {
104
+ "companies-house": [
105
+ "UKCompaniesHouseRegisteredNumber",
106
+ "EntityCurrentLegalOrRegisteredName",
107
+ "BalanceSheetDate",
108
+ "DateAuthorisationFinancialStatementsForIssue",
109
+ "DirectorSigningFinancialStatements",
110
+ "EntityDormantTruefalse",
111
+ "EntityTradingStatus",
112
+ "AccountsStatusAuditedOrUnaudited",
113
+ "AccountsTypeFullOrAbbreviated",
114
+ "AccountingStandardsApplied",
115
+ "LegalFormEntity",
116
+ "StartDateForPeriodCoveredByReport",
117
+ "EndDateForPeriodCoveredByReport",
118
+ "CharityRegistrationNumberEnglandWales",
119
+ "CharityRegistrationNumberScotland",
120
+ "CharityRegistrationNumberNorthernIreland"
121
+ ]
122
+ }