ssb-dash-framework 0.2.2__tar.gz → 0.2.2a0__tar.gz
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.
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/PKG-INFO +1 -1
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/pyproject.toml +1 -1
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/__init__.py +0 -4
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/assets/dashAgGridFunctions.js +10 -37
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/assets/stylesheet.css +0 -13
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/control/control_framework_base.py +14 -41
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/__init__.py +0 -2
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_control_view.py +11 -19
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_history.py +5 -14
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_primary_table.py +37 -58
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_supporting_table.py +3 -21
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/bofregistry.py +31 -27
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/macro_module.py +73 -260
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/parquet_editor.py +26 -176
- ssb_dash_framework-0.2.2a0/src/ssb_dash_framework/utils/core_query_functions.py +83 -0
- ssb_dash_framework-0.2.2/src/ssb_dash_framework/utils/core_query_functions.py +0 -170
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/LICENSE +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/README.md +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/__main__.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/control/__init__.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/aarsregnskap.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/agg_dist_plotter.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_data_capture.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/__init__.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_comment.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_contact.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_control.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_main_view.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_submitted_forms.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_unit_details.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_utility.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/bedriftstabell.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/building_blocks/__init__.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/building_blocks/canvas.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/building_blocks/figuredisplay.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/building_blocks/map_display.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/building_blocks/multimodule.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/building_blocks/tables.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/freesearch.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/hb_method.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/nspek.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/pi_memorizer.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/skjemapdfviewer.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/visualizationbuilder.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/py.typed +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/setup/__init__.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/setup/app_setup.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/setup/main_layout.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/setup/variableselector.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/__init__.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/alert_handler.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/app_logger.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/datahelper.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/debugger_modal.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/eimerdb_helpers.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/functions.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/implementations.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/module_validation.py +0 -0
- {ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/utils/r_helpers.py +0 -0
|
@@ -60,7 +60,6 @@ from .modules import VisualizationBuilder
|
|
|
60
60
|
from .modules import VisualizationBuilderWindow
|
|
61
61
|
from .modules import apply_edits
|
|
62
62
|
from .modules import export_from_parqueteditor
|
|
63
|
-
from .modules import get_export_log_path
|
|
64
63
|
from .modules import get_log_path
|
|
65
64
|
from .setup import VariableSelector
|
|
66
65
|
from .setup import VariableSelectorOption
|
|
@@ -81,7 +80,6 @@ from .utils import create_database
|
|
|
81
80
|
from .utils import create_database_engine
|
|
82
81
|
from .utils import enable_app_logging
|
|
83
82
|
from .utils import hb_method
|
|
84
|
-
from .utils import ibis_filter_with_dict
|
|
85
83
|
from .utils import module_validator
|
|
86
84
|
from .utils import sidebar_button
|
|
87
85
|
|
|
@@ -166,9 +164,7 @@ __all__ = [
|
|
|
166
164
|
"create_database_engine",
|
|
167
165
|
"enable_app_logging",
|
|
168
166
|
"export_from_parqueteditor",
|
|
169
|
-
"get_export_log_path",
|
|
170
167
|
"get_log_path",
|
|
171
|
-
"ibis_filter_with_dict",
|
|
172
168
|
"main_layout",
|
|
173
169
|
"module_validator",
|
|
174
170
|
"register_control",
|
|
@@ -155,12 +155,11 @@ window.dashAgGridFunctions.MacroModule = {
|
|
|
155
155
|
|
|
156
156
|
// === Function displayDiffHighlight (Compare current cell's value to previous year, highlight if different) ===
|
|
157
157
|
displayDiffHighlight(props) {
|
|
158
|
-
|
|
159
|
-
if (!props.data) return {};
|
|
160
|
-
|
|
161
158
|
const field = props.colDef.field;
|
|
162
159
|
const value = props.value;
|
|
163
160
|
|
|
161
|
+
if (!props.data) return {};
|
|
162
|
+
|
|
164
163
|
const normalize = (v) =>
|
|
165
164
|
v !== null && v !== undefined ? String(v).trim() : "";
|
|
166
165
|
|
|
@@ -191,6 +190,14 @@ window.dashAgGridFunctions.MacroModule = {
|
|
|
191
190
|
return {}; // no change
|
|
192
191
|
}
|
|
193
192
|
|
|
193
|
+
// all other columns
|
|
194
|
+
if (field.endsWith("_x")) {
|
|
195
|
+
return {
|
|
196
|
+
backgroundColor: '#e8e9eb',
|
|
197
|
+
color: 'black'
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
194
201
|
const prevField = field + "_x";
|
|
195
202
|
const prevValue = normalize(props.data[prevField]);
|
|
196
203
|
const currentValue = normalize(value);
|
|
@@ -221,40 +228,6 @@ window.dashAgGridFunctions.MacroModule = {
|
|
|
221
228
|
const prefixF = String(naringF).substring(0, 2);
|
|
222
229
|
|
|
223
230
|
return prefixB !== prefixF;
|
|
224
|
-
},
|
|
225
|
-
|
|
226
|
-
// === Function displayDiffColumnHighlight (Mark tilgang & avgang on the diff-column) ===
|
|
227
|
-
displayDiffColumnHighlight(props) {
|
|
228
|
-
if (!props.data) return {};
|
|
229
|
-
|
|
230
|
-
const field = props.colDef.field;
|
|
231
|
-
|
|
232
|
-
const isDiffColumn = field.endsWith("_diff");
|
|
233
|
-
const isExitHighlightField =
|
|
234
|
-
(field === "orgnr_b" || field === "navn") &&
|
|
235
|
-
props.data.is_avgang &&
|
|
236
|
-
props.data.is_exiter;
|
|
237
|
-
|
|
238
|
-
// Guard: only apply to allowed columns
|
|
239
|
-
if (!isDiffColumn && !isExitHighlightField) return {};
|
|
240
|
-
|
|
241
|
-
// tilgang (still only for diff columns)
|
|
242
|
-
if (isDiffColumn && props.data.is_tilgang) {
|
|
243
|
-
return {
|
|
244
|
-
backgroundColor: "#c7f5c7",
|
|
245
|
-
color: "black",
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// avgang (diff columns OR exiter name/orgnr)
|
|
250
|
-
if (props.data.is_avgang) {
|
|
251
|
-
return {
|
|
252
|
-
backgroundColor: "#ffc7c7",
|
|
253
|
-
color: "black",
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return {};
|
|
258
231
|
}
|
|
259
232
|
|
|
260
233
|
};
|
{ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/assets/stylesheet.css
RENAMED
|
@@ -230,19 +230,6 @@ Altinn Editor History
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
|
|
233
|
-
/*
|
|
234
|
-
Altinn Editor Support Tables
|
|
235
|
-
*/
|
|
236
|
-
.hjelpetabeller-modal .modal-dialog {
|
|
237
|
-
max-width: 90vw !important;
|
|
238
|
-
width: 90vw !important;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.hjelpetabeller-modal .modal-content {
|
|
242
|
-
height: 70vh !important;
|
|
243
|
-
overflow: hidden;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
233
|
/*
|
|
247
234
|
MacroModule
|
|
248
235
|
*/
|
|
@@ -227,7 +227,8 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
227
227
|
self.conn.insert("kontroller", rows_to_register)
|
|
228
228
|
elif conn_is_ibis(self.conn):
|
|
229
229
|
conn = self.conn
|
|
230
|
-
conn.
|
|
230
|
+
k = conn.table("kontroller") # type: ignore[attr-defined]
|
|
231
|
+
k.insert(rows_to_register)
|
|
231
232
|
else:
|
|
232
233
|
raise NotImplementedError(
|
|
233
234
|
f"Connection type '{type(self.conn)}' is currently not implemented."
|
|
@@ -323,6 +324,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
323
324
|
"""
|
|
324
325
|
logger.info(f"Running control: {control}")
|
|
325
326
|
results = getattr(self, control)()
|
|
327
|
+
|
|
326
328
|
logger.debug("Starting validation of results.")
|
|
327
329
|
if not isinstance(results, pd.DataFrame):
|
|
328
330
|
raise TypeError(
|
|
@@ -346,14 +348,10 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
346
348
|
raise ValueError(
|
|
347
349
|
f"Error when running {control}. Could not find {results['kontrollid'].unique()} among registered controls. Valid options retrieved from the 'kontrollutslag' table: {self.controls}"
|
|
348
350
|
)
|
|
349
|
-
|
|
350
|
-
# IMPORTANT! This code must not fix the error for the user.
|
|
351
|
-
# This check exists because it is expected that users mistakenly forget to filter on periods / form type
|
|
352
|
-
# and that forgetting that filtering WILL cause false positives/negatives. Do not change this validation check.
|
|
353
351
|
for key, value in self.applies_to_subset.items():
|
|
354
352
|
if len(results[key].unique()) != 1:
|
|
355
353
|
raise ValueError(
|
|
356
|
-
f"Results from control
|
|
354
|
+
f"Results from control {control} has too many unique values for '{key}'. Expected '{value[0]}'. Received: '{results[key].unique()}'"
|
|
357
355
|
)
|
|
358
356
|
if not value[0] == results[key].unique()[0]:
|
|
359
357
|
raise ValueError(
|
|
@@ -440,10 +438,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
440
438
|
else:
|
|
441
439
|
specific_control = None
|
|
442
440
|
existing_kontrollutslag = self.get_current_kontrollutslag(specific_control)
|
|
443
|
-
if existing_kontrollutslag is not None
|
|
444
|
-
logger.debug(
|
|
445
|
-
f"Merging new results with existing results.\nNew:{control_results.shape}\n{control_results.head(10)}\n\nExisting:{existing_kontrollutslag.shape}\n{existing_kontrollutslag.head(10)}"
|
|
446
|
-
)
|
|
441
|
+
if existing_kontrollutslag is not None:
|
|
447
442
|
control_results = control_results.merge(
|
|
448
443
|
existing_kontrollutslag,
|
|
449
444
|
on=[*self.applies_to_subset.keys(), "kontrollid", "ident", "refnr"],
|
|
@@ -457,7 +452,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
457
452
|
"kontrollid",
|
|
458
453
|
"ident",
|
|
459
454
|
"refnr",
|
|
460
|
-
"verdi_x"
|
|
455
|
+
"verdi_x",
|
|
461
456
|
"utslag_x",
|
|
462
457
|
]
|
|
463
458
|
]
|
|
@@ -475,7 +470,8 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
475
470
|
self.conn.insert("kontrollutslag", control_results)
|
|
476
471
|
elif conn_is_ibis(self.conn):
|
|
477
472
|
conn = self.conn
|
|
478
|
-
conn.
|
|
473
|
+
k = conn.table("kontrollutslag") # type: ignore[attr-defined]
|
|
474
|
+
k.insert(control_results)
|
|
479
475
|
else:
|
|
480
476
|
raise NotImplementedError(
|
|
481
477
|
f"Connection type '{type(self.conn)}' is currently not implemented."
|
|
@@ -498,48 +494,25 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
|
|
|
498
494
|
logger.info("No existing rows found, ending here.")
|
|
499
495
|
return None
|
|
500
496
|
else:
|
|
501
|
-
logger.debug(
|
|
502
|
-
f"Merging new results with existing results.\nNew:{control_results.shape}\n{control_results.head(10)}\n\nExisting:{existing_kontrollutslag.shape}\n{existing_kontrollutslag.head(10)}"
|
|
503
|
-
)
|
|
504
497
|
control_results = control_results.merge(
|
|
505
498
|
existing_kontrollutslag,
|
|
506
|
-
on=[
|
|
499
|
+
on=["kontrollid", "ident", "refnr"],
|
|
507
500
|
how="outer",
|
|
508
501
|
indicator=True,
|
|
509
|
-
)
|
|
510
|
-
logger.debug(f"{control_results}")
|
|
511
|
-
control_results = control_results.dropna(
|
|
512
|
-
subset=[col for col in control_results if col != "verdi"]
|
|
513
|
-
) # TODO: Check if this causes unexpected behavior.
|
|
502
|
+
).dropna()
|
|
514
503
|
if control_results.empty:
|
|
515
|
-
logger.debug(f"Empty control_results:\n{control_results}")
|
|
516
504
|
raise ValueError(
|
|
517
|
-
"Combined results from 'control_results' and 'existing_kontrollutslag' is empty
|
|
505
|
+
"Combined results from 'control_results' and 'existing_kontrollutslag' is empty."
|
|
518
506
|
)
|
|
519
507
|
logger.debug(control_results)
|
|
520
508
|
logger.debug(
|
|
521
509
|
f"Utslag left:\n{control_results['utslag_x'].value_counts()}\nUtslag right:\n{control_results['utslag_y'].value_counts()}"
|
|
522
510
|
)
|
|
523
|
-
changed = control_results[
|
|
511
|
+
changed = control_results[
|
|
524
512
|
control_results["utslag_x"] != control_results["utslag_y"]
|
|
525
|
-
][
|
|
526
|
-
|
|
527
|
-
*self.time_units,
|
|
528
|
-
"kontrollid",
|
|
529
|
-
"ident",
|
|
530
|
-
"refnr",
|
|
531
|
-
"verdi_x" if "verdi_x" in control_results.columns else "verdi",
|
|
532
|
-
"utslag_x",
|
|
533
|
-
]
|
|
534
|
-
].rename(
|
|
535
|
-
columns={"utslag_x": "utslag"}
|
|
513
|
+
][["kontrollid", "ident", "refnr", "verdi_x", "utslag_x"]].rename(
|
|
514
|
+
columns={"utslag_x": "utslag", "verdi_x": "verdi"}
|
|
536
515
|
)
|
|
537
|
-
if "verdi_x" in changed.columns:
|
|
538
|
-
changed = changed.rename(columns={"verdi_x": "verdi"})
|
|
539
|
-
|
|
540
|
-
missing = set(self._required_kontrollutslag_columns) - set(changed.columns)
|
|
541
|
-
if missing:
|
|
542
|
-
raise ValueError(f"Missing required columns: {missing}")
|
|
543
516
|
if changed.empty:
|
|
544
517
|
logger.info("No changed rows, ending here.")
|
|
545
518
|
return None
|
{ssb_dash_framework-0.2.2 → ssb_dash_framework-0.2.2a0}/src/ssb_dash_framework/modules/__init__.py
RENAMED
|
@@ -52,7 +52,6 @@ from .parquet_editor import ParquetEditor
|
|
|
52
52
|
from .parquet_editor import ParquetEditorChangelog
|
|
53
53
|
from .parquet_editor import apply_edits
|
|
54
54
|
from .parquet_editor import export_from_parqueteditor
|
|
55
|
-
from .parquet_editor import get_export_log_path
|
|
56
55
|
from .parquet_editor import get_log_path
|
|
57
56
|
from .pi_memorizer import PimemorizerTab
|
|
58
57
|
from .skjemapdfviewer import SkjemapdfViewer
|
|
@@ -120,6 +119,5 @@ __all__ = [
|
|
|
120
119
|
"VisualizationBuilderWindow",
|
|
121
120
|
"apply_edits",
|
|
122
121
|
"export_from_parqueteditor",
|
|
123
|
-
"get_export_log_path",
|
|
124
122
|
"get_log_path",
|
|
125
123
|
]
|
|
@@ -54,19 +54,15 @@ class ControlView(ABC):
|
|
|
54
54
|
control_dict: A dictionary with one control class per skjema.
|
|
55
55
|
conn: The eimerdb connection.
|
|
56
56
|
outputs: Variable selector fields to output to. Defaults to ['ident']
|
|
57
|
-
|
|
58
|
-
Raises:
|
|
59
|
-
TypeError: if conn type is not 'EimerDBInstance' or ibis connection.
|
|
60
57
|
"""
|
|
61
58
|
logger.warning(
|
|
62
59
|
f"{self.__class__.__name__} is under development and may change in future releases."
|
|
63
60
|
)
|
|
64
61
|
if outputs is None:
|
|
65
62
|
outputs = ["ident"]
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)
|
|
63
|
+
assert hasattr(
|
|
64
|
+
conn, "query"
|
|
65
|
+
), "The database connection object must have a 'query' method."
|
|
70
66
|
self.module_number = ControlView._id_number
|
|
71
67
|
self.module_name = self.__class__.__name__
|
|
72
68
|
ControlView._id_number += 1
|
|
@@ -176,11 +172,13 @@ class ControlView(ABC):
|
|
|
176
172
|
Input("var-altinnskjema", "value"),
|
|
177
173
|
self.variableselector.get_all_inputs(),
|
|
178
174
|
)
|
|
179
|
-
def kontroller_show_selected_controls(skjema: str
|
|
175
|
+
def kontroller_show_selected_controls(skjema: str, *args: Any):
|
|
180
176
|
logger.debug(f"Args:\nskjema: {skjema}\nargs: {args}")
|
|
181
177
|
partition_args = dict(zip(self.time_units, args, strict=False))
|
|
182
178
|
if partition_args is not None and skjema is not None:
|
|
183
|
-
valgte_vars =
|
|
179
|
+
valgte_vars = (
|
|
180
|
+
f"valgt partisjon: {partition_args}\nvalgt skjema: {skjema}"
|
|
181
|
+
)
|
|
184
182
|
return valgte_vars
|
|
185
183
|
|
|
186
184
|
@callback(
|
|
@@ -189,9 +187,7 @@ class ControlView(ABC):
|
|
|
189
187
|
State("alert_store", "data"),
|
|
190
188
|
prevent_initial_call=True,
|
|
191
189
|
)
|
|
192
|
-
def alert_user_of_controls(
|
|
193
|
-
click: int | None, alert_store: list[dict[str, Any]]
|
|
194
|
-
) -> list[dict[str, Any]]:
|
|
190
|
+
def alert_user_of_controls(click, alert_store):
|
|
195
191
|
return [
|
|
196
192
|
create_alert(
|
|
197
193
|
"Kjører kontroller, dette kan ta litt tid, du får beskjed når den er ferdig. Ikke klikk på knappen igjen.",
|
|
@@ -213,11 +209,7 @@ class ControlView(ABC):
|
|
|
213
209
|
prevent_initial_call=True,
|
|
214
210
|
)
|
|
215
211
|
def get_kontroller_overview(
|
|
216
|
-
skjema: str,
|
|
217
|
-
refresh: int | None,
|
|
218
|
-
rerun: int | None,
|
|
219
|
-
alert_store: list[dict[str, Any]],
|
|
220
|
-
*args: Any,
|
|
212
|
+
skjema: str, refresh: int | None, rerun: int | None, alert_store, *args: Any
|
|
221
213
|
):
|
|
222
214
|
logger.debug(
|
|
223
215
|
f"Args:\n"
|
|
@@ -310,7 +302,7 @@ class ControlView(ABC):
|
|
|
310
302
|
utslag = (
|
|
311
303
|
kontrollutslag.filter(kontrollutslag.utslag == True)
|
|
312
304
|
.group_by(kontrollutslag.kontrollid)
|
|
313
|
-
.aggregate(ant_utslag=
|
|
305
|
+
.aggregate(ant_utslag=kontrollutslag.row_id.count())
|
|
314
306
|
)
|
|
315
307
|
|
|
316
308
|
subq = (
|
|
@@ -327,7 +319,7 @@ class ControlView(ABC):
|
|
|
327
319
|
)
|
|
328
320
|
.filter(kontrollutslag.utslag == True)
|
|
329
321
|
.group_by(kontrollutslag.kontrollid)
|
|
330
|
-
.aggregate(uediterte=
|
|
322
|
+
.aggregate(uediterte=kontrollutslag.row_id.count())
|
|
331
323
|
.select("kontrollid", "uediterte")
|
|
332
324
|
)
|
|
333
325
|
|
|
@@ -12,7 +12,6 @@ from dash.dependencies import State
|
|
|
12
12
|
from dash.exceptions import PreventUpdate
|
|
13
13
|
from eimerdb import EimerDBInstance
|
|
14
14
|
from ibis import _
|
|
15
|
-
import tzlocal
|
|
16
15
|
|
|
17
16
|
from ssb_dash_framework.utils import conn_is_ibis
|
|
18
17
|
|
|
@@ -21,8 +20,6 @@ from ...utils.eimerdb_helpers import create_partition_select
|
|
|
21
20
|
|
|
22
21
|
logger = logging.getLogger(__name__)
|
|
23
22
|
|
|
24
|
-
local_tz = tzlocal.get_localzone()
|
|
25
|
-
|
|
26
23
|
|
|
27
24
|
class AltinnEditorHistory:
|
|
28
25
|
"""Module for viewing the editing history for the selected observation."""
|
|
@@ -67,12 +64,10 @@ class AltinnEditorHistory:
|
|
|
67
64
|
dbc.ModalBody(
|
|
68
65
|
dag.AgGrid(
|
|
69
66
|
defaultColDef={
|
|
67
|
+
"editable": True,
|
|
70
68
|
"filter": True,
|
|
71
69
|
"resizable": True,
|
|
72
70
|
},
|
|
73
|
-
dashGridOptions={
|
|
74
|
-
"enableCellTextSelection": True,
|
|
75
|
-
},
|
|
76
71
|
id="skjemadata-historikkmodal-table1",
|
|
77
72
|
className="ag-theme-alpine header-style-on-filter",
|
|
78
73
|
columnSize="responsiveSizeToFit",
|
|
@@ -158,15 +153,11 @@ class AltinnEditorHistory:
|
|
|
158
153
|
if conn_is_ibis(self.conn):
|
|
159
154
|
conn = self.conn
|
|
160
155
|
t = conn.table("skjemadataendringshistorikk")
|
|
161
|
-
df =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
.
|
|
165
|
-
.dt.floor("s")
|
|
166
|
-
.dt.tz_localize(None)
|
|
167
|
-
.dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
156
|
+
df = (
|
|
157
|
+
t.filter(_.refnr == refnr)
|
|
158
|
+
.order_by(_.endret_tid.cast("timestamp").desc())
|
|
159
|
+
.to_pandas()
|
|
168
160
|
)
|
|
169
|
-
df = df.sort_values("endret_tid", ascending=False)
|
|
170
161
|
columns = [
|
|
171
162
|
{
|
|
172
163
|
"headerName": col,
|
|
@@ -119,41 +119,18 @@ class AltinnEditorPrimaryTable:
|
|
|
119
119
|
def module_callbacks(self) -> None:
|
|
120
120
|
"""Defines the callbacks for the module."""
|
|
121
121
|
|
|
122
|
-
# check if var-bedrift exists
|
|
123
|
-
try:
|
|
124
|
-
self.variableselector.get_option("var-bedrift", search_target="id")
|
|
125
|
-
has_bedrift = True
|
|
126
|
-
except ValueError:
|
|
127
|
-
has_bedrift = False
|
|
128
|
-
logger.debug("var-bedrift not available, skipping bedrift sorting")
|
|
129
|
-
|
|
130
122
|
@callback( # type: ignore[misc]
|
|
131
123
|
Output("altinnedit-table-skjemadata", "rowData", allow_duplicate=True),
|
|
132
124
|
Output("altinnedit-table-skjemadata", "columnDefs", allow_duplicate=True),
|
|
133
125
|
Input("altinnedit-refnr", "value"),
|
|
134
126
|
Input("altinnedit-option1", "value"),
|
|
135
|
-
Input("var-ident", "value"),
|
|
136
127
|
State("altinnedit-skjemaer", "value"),
|
|
137
|
-
(
|
|
138
|
-
State("var-bedrift", "value")
|
|
139
|
-
if has_bedrift
|
|
140
|
-
else State("altinnedit-refnr", "value")
|
|
141
|
-
), # Dummy state if no bedrift
|
|
142
128
|
self.variableselector.get_all_states(),
|
|
143
129
|
prevent_initial_call=True,
|
|
144
130
|
)
|
|
145
131
|
def hovedside_update_altinnskjema(
|
|
146
|
-
refnr: str,
|
|
147
|
-
tabell: str,
|
|
148
|
-
ident: str,
|
|
149
|
-
skjema: str,
|
|
150
|
-
bedrift_or_dummy: str,
|
|
151
|
-
*args: Any,
|
|
132
|
+
refnr: str, tabell: str, skjema: str, *args: Any
|
|
152
133
|
) -> tuple[list[dict[str, Any]] | None, list[dict[str, Any]] | None]:
|
|
153
|
-
|
|
154
|
-
# extract bedrift if it exists
|
|
155
|
-
bedrift = bedrift_or_dummy if has_bedrift else None
|
|
156
|
-
|
|
157
134
|
logger.debug(
|
|
158
135
|
f"Args:\n"
|
|
159
136
|
f"refnr: {refnr}\n"
|
|
@@ -202,20 +179,12 @@ class AltinnEditorPrimaryTable:
|
|
|
202
179
|
f"partition_select:\n{create_partition_select(desired_partitions=self.time_units,skjema=skjema,**partition_args,)}"
|
|
203
180
|
)
|
|
204
181
|
|
|
205
|
-
t =
|
|
182
|
+
t = (
|
|
183
|
+
t.filter(_.refnr == refnr)
|
|
184
|
+
.join(d, "variabel", how="left")
|
|
185
|
+
.order_by(_.radnr)
|
|
186
|
+
)
|
|
206
187
|
t = t.filter(ibis_filter_with_dict(filter_dict))
|
|
207
|
-
|
|
208
|
-
# sort by bedrift if available
|
|
209
|
-
if bedrift and "ident" in t.columns:
|
|
210
|
-
t = t.mutate(
|
|
211
|
-
sort_priority=ibis.case()
|
|
212
|
-
.when(_.ident == bedrift, 0)
|
|
213
|
-
.else_(1)
|
|
214
|
-
.end()
|
|
215
|
-
).order_by(["sort_priority", _.radnr])
|
|
216
|
-
else:
|
|
217
|
-
t = t.order_by(_.radnr)
|
|
218
|
-
|
|
219
188
|
df = t.drop(
|
|
220
189
|
[col for col in t.columns if col.endswith("_right")]
|
|
221
190
|
+ ["datatype", "radnr", "tabell"]
|
|
@@ -256,13 +225,6 @@ class AltinnEditorPrimaryTable:
|
|
|
256
225
|
.to_pandas()
|
|
257
226
|
)
|
|
258
227
|
|
|
259
|
-
# sort by bedrift if it exists
|
|
260
|
-
if bedrift and "ident" in df.columns:
|
|
261
|
-
df = df.sort_values(
|
|
262
|
-
by="ident",
|
|
263
|
-
key=lambda x: x.map(lambda v: 0 if v == bedrift else 1),
|
|
264
|
-
)
|
|
265
|
-
|
|
266
228
|
columndefs = [
|
|
267
229
|
{
|
|
268
230
|
"headerName": col,
|
|
@@ -287,6 +249,35 @@ class AltinnEditorPrimaryTable:
|
|
|
287
249
|
)
|
|
288
250
|
return None, None
|
|
289
251
|
|
|
252
|
+
try: # TODO Find better solution to sort - config file?
|
|
253
|
+
self.variableselector.get_option("var-bedrift", search_target="id")
|
|
254
|
+
|
|
255
|
+
@callback(
|
|
256
|
+
Output("altinnedit-table-skjemadata", "rowData"),
|
|
257
|
+
Output("altinnedit-table-skjemadata", "columnDefs"),
|
|
258
|
+
Input("altinnedit-table-skjemadata", "rowData"),
|
|
259
|
+
Input("altinnedit-table-skjemadata", "columnDefs"),
|
|
260
|
+
State("var-bedrift", "value"),
|
|
261
|
+
prevent_initial_call=True,
|
|
262
|
+
)
|
|
263
|
+
def sort_by_bedrift(
|
|
264
|
+
row_data: list[dict[str, Any]],
|
|
265
|
+
column_defs: list[dict[str, Any]],
|
|
266
|
+
bedrift: str,
|
|
267
|
+
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
|
268
|
+
"""Sort table to prioritize selected bedrift."""
|
|
269
|
+
if not bedrift or not row_data:
|
|
270
|
+
return row_data, column_defs
|
|
271
|
+
|
|
272
|
+
sorted_data = sorted(
|
|
273
|
+
row_data, key=lambda row: 0 if row.get("ident") == bedrift else 1
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
return sorted_data, column_defs
|
|
277
|
+
|
|
278
|
+
except ValueError:
|
|
279
|
+
logger.debug("var-bedrift not available, skipping bedrift sorting callback")
|
|
280
|
+
|
|
290
281
|
@callback( # type: ignore[misc]
|
|
291
282
|
Output("var-statistikkvariabel", "value"),
|
|
292
283
|
Input("altinnedit-table-skjemadata", "cellClicked"),
|
|
@@ -296,21 +287,9 @@ class AltinnEditorPrimaryTable:
|
|
|
296
287
|
click: dict[str, Any], row_data: list[dict[str, Any]]
|
|
297
288
|
) -> str:
|
|
298
289
|
logger.debug(f"Args:\nclick: {click}\nrow_data: {row_data}")
|
|
299
|
-
|
|
300
|
-
if not click or not row_data:
|
|
290
|
+
if not click:
|
|
301
291
|
raise PreventUpdate
|
|
302
|
-
|
|
303
|
-
columns = list(row_data[0].keys())
|
|
304
|
-
|
|
305
|
-
long_format = "variabel" in columns and "verdi" in columns
|
|
306
|
-
if long_format:
|
|
307
|
-
return str(row_data[click["rowIndex"]]["variabel"])
|
|
308
|
-
|
|
309
|
-
column = click.get("colId") # wide format
|
|
310
|
-
if column in ("aar", "ident", "skjema", "refnr", "tabell"):
|
|
311
|
-
raise PreventUpdate
|
|
312
|
-
|
|
313
|
-
return str(column)
|
|
292
|
+
return str(row_data[click["rowIndex"]]["variabel"])
|
|
314
293
|
|
|
315
294
|
@callback( # type: ignore[misc]
|
|
316
295
|
Output("alert_store", "data", allow_duplicate=True),
|
|
@@ -39,8 +39,6 @@ class AltinnSupportTable:
|
|
|
39
39
|
get_data_func: Callable[..., pd.DataFrame],
|
|
40
40
|
editor_inputs: list[str] | None = None,
|
|
41
41
|
variableselector: VariableSelector | None = None,
|
|
42
|
-
pin_leftmost_column: bool = True,
|
|
43
|
-
suffix_to_colour_grey: list[str] | None = None,
|
|
44
42
|
) -> None:
|
|
45
43
|
"""Initializes the support table.
|
|
46
44
|
|
|
@@ -49,8 +47,6 @@ class AltinnSupportTable:
|
|
|
49
47
|
get_data_func: Function that returns data to show in the supporting table.
|
|
50
48
|
editor_inputs: List of inputs from the AltinnSkjemadataEditor to use as arguments in the get_data_func.
|
|
51
49
|
variableselector: VariableSelector instance for adding arguments from the overall variableselector.
|
|
52
|
-
pin_leftmost_column: Optional. Boolean to pin the leftmost column in the AgGrid (usually the ident-col). Defaults to "True".
|
|
53
|
-
suffix_to_colour_grey: Optional. List of column-name suffixes to colour light grey in the AgGrid. Defaults to "[_x]".
|
|
54
50
|
|
|
55
51
|
Note:
|
|
56
52
|
The component is automatically added to the panel inside the modal.
|
|
@@ -58,8 +54,6 @@ class AltinnSupportTable:
|
|
|
58
54
|
self.label = label
|
|
59
55
|
self.inputs = editor_inputs
|
|
60
56
|
self.get_data_func = get_data_func
|
|
61
|
-
self.pin_leftmost_column = pin_leftmost_column
|
|
62
|
-
self.suffix_to_colour_grey = suffix_to_colour_grey or ["_x"]
|
|
63
57
|
if variableselector:
|
|
64
58
|
self.variableselector = variableselector
|
|
65
59
|
else:
|
|
@@ -82,10 +76,8 @@ class AltinnSupportTable:
|
|
|
82
76
|
"""The content to show in the support table."""
|
|
83
77
|
return html.Div(
|
|
84
78
|
dag.AgGrid(
|
|
85
|
-
defaultColDef={"editable": False
|
|
86
|
-
dashGridOptions={"enableCellTextSelection": True},
|
|
79
|
+
defaultColDef={"editable": False},
|
|
87
80
|
id=f"support-table-{self.suptable_id}",
|
|
88
|
-
style={"height": "700px"},
|
|
89
81
|
)
|
|
90
82
|
)
|
|
91
83
|
|
|
@@ -103,17 +95,7 @@ class AltinnSupportTable:
|
|
|
103
95
|
f"Running get_data_func for table '{self.label}' using args: {args}"
|
|
104
96
|
)
|
|
105
97
|
data = self.get_data_func(*args)
|
|
106
|
-
|
|
107
|
-
for col in data.columns:
|
|
108
|
-
col_def: dict[str, Any] = {"field": col, "headerName": col.lower()}
|
|
109
|
-
if self.suffix_to_colour_grey and col.endswith(
|
|
110
|
-
tuple(self.suffix_to_colour_grey)
|
|
111
|
-
):
|
|
112
|
-
col_def["cellStyle"] = {"backgroundColor": "#e8e9eb"}
|
|
113
|
-
column_defs.append(col_def)
|
|
114
|
-
if self.pin_leftmost_column and column_defs:
|
|
115
|
-
column_defs[0]["pinned"] = "left"
|
|
116
|
-
return data.to_dict("records"), column_defs
|
|
98
|
+
return data.to_dict("records"), [{"field": col} for col in data.columns]
|
|
117
99
|
|
|
118
100
|
def support_table_layout(self) -> dbc.Tab:
|
|
119
101
|
"""Creates the layout."""
|
|
@@ -197,7 +179,7 @@ class AltinnEditorSupportTables:
|
|
|
197
179
|
],
|
|
198
180
|
id="skjemadata-hjelpetabellmodal",
|
|
199
181
|
is_open=False,
|
|
200
|
-
|
|
182
|
+
size="xl",
|
|
201
183
|
)
|
|
202
184
|
logger.debug("Created support tables modal")
|
|
203
185
|
return hjelpetabellmodal
|