Adjust navigation to multiple apps, shared pages

This commit is contained in:
Jan Kvetina 2022-01-02 13:46:27 +01:00
parent 911770c2cd
commit f58c983936
5 changed files with 224 additions and 42 deletions

View File

@ -22,7 +22,7 @@ wwv_flow_api.create_page(
,p_page_template_options=>'#DEFAULT#'
,p_required_role=>wwv_flow_api.id(9556407311505078)
,p_last_updated_by=>'DEV'
,p_last_upd_yyyymmddhh24miss=>'20220101183201'
,p_last_upd_yyyymmddhh24miss=>'20220102090736'
);
wwv_flow_api.create_page_plug(
p_id=>wwv_flow_api.id(9192009232668637)
@ -49,6 +49,7 @@ wwv_flow_api.create_page_plug(
,p_plug_display_point=>'BODY'
,p_query_type=>'TABLE'
,p_query_table=>'NAV_OVERVIEW'
,p_query_where=>'app_id = app.get_app_id()'
,p_include_rowid_column=>false
,p_plug_source_type=>'NATIVE_IG'
,p_plug_query_options=>'DERIVED_REPORT_COLUMNS'
@ -373,7 +374,7 @@ wwv_flow_api.create_region_column(
,p_item_type=>'NATIVE_DISPLAY_ONLY'
,p_heading=>'Css Class'
,p_heading_alignment=>'LEFT'
,p_display_sequence=>170
,p_display_sequence=>180
,p_value_alignment=>'LEFT'
,p_attribute_02=>'VALUE'
,p_attribute_05=>'PLAIN'
@ -399,7 +400,7 @@ wwv_flow_api.create_region_column(
,p_item_type=>'NATIVE_DISPLAY_ONLY'
,p_heading=>'Auth Scheme'
,p_heading_alignment=>'LEFT'
,p_display_sequence=>180
,p_display_sequence=>190
,p_value_alignment=>'LEFT'
,p_attribute_02=>'VALUE'
,p_attribute_05=>'PLAIN'
@ -471,7 +472,7 @@ wwv_flow_api.create_region_column(
,p_data_type=>'VARCHAR2'
,p_is_query_only=>true
,p_item_type=>'NATIVE_HIDDEN'
,p_display_sequence=>190
,p_display_sequence=>200
,p_attribute_01=>'Y'
,p_use_as_row_header=>false
,p_enable_sort_group=>true
@ -489,7 +490,7 @@ wwv_flow_api.create_region_column(
,p_item_type=>'NATIVE_DISPLAY_ONLY'
,p_heading=>'Sort Order'
,p_heading_alignment=>'LEFT'
,p_display_sequence=>200
,p_display_sequence=>210
,p_value_alignment=>'LEFT'
,p_attribute_02=>'VALUE'
,p_attribute_05=>'PLAIN'
@ -505,6 +506,39 @@ wwv_flow_api.create_region_column(
,p_is_primary_key=>false
,p_include_in_export=>true
);
wwv_flow_api.create_region_column(
p_id=>wwv_flow_api.id(12994588754936905)
,p_name=>'IS_SHARED'
,p_source_type=>'DB_COLUMN'
,p_source_expression=>'IS_SHARED'
,p_data_type=>'VARCHAR2'
,p_is_query_only=>false
,p_item_type=>'NATIVE_SINGLE_CHECKBOX'
,p_heading=>'Is Shared'
,p_heading_alignment=>'CENTER'
,p_display_sequence=>170
,p_value_alignment=>'CENTER'
,p_attribute_01=>'N'
,p_attribute_02=>'Y'
,p_is_required=>false
,p_enable_filter=>true
,p_filter_operators=>'C:S:CASE_INSENSITIVE:REGEXP'
,p_filter_is_required=>false
,p_filter_text_case=>'MIXED'
,p_filter_exact_match=>true
,p_filter_lov_type=>'DISTINCT'
,p_use_as_row_header=>false
,p_enable_sort_group=>true
,p_enable_control_break=>true
,p_enable_hide=>true
,p_is_primary_key=>false
,p_duplicate_value=>true
,p_include_in_export=>true
,p_display_condition_type=>'EXPRESSION'
,p_display_condition=>'app.get_app_id() = app.get_core_app_id()'
,p_display_condition2=>'PLSQL'
,p_security_scheme=>wwv_flow_api.id(9556407311505078)
);
wwv_flow_api.create_interactive_grid(
p_id=>wwv_flow_api.id(9192298818668639)
,p_internal_uid=>9192298818668639
@ -567,7 +601,7 @@ wwv_flow_api.create_ig_report_column(
wwv_flow_api.create_ig_report_column(
p_id=>wwv_flow_api.id(3864884157089)
,p_view_id=>wwv_flow_api.id(9266000528438793)
,p_display_seq=>14
,p_display_seq=>15
,p_column_id=>wwv_flow_api.id(10245444031410343)
,p_is_visible=>false
,p_is_frozen=>false
@ -665,7 +699,7 @@ wwv_flow_api.create_ig_report_column(
wwv_flow_api.create_ig_report_column(
p_id=>wwv_flow_api.id(9275579147438822)
,p_view_id=>wwv_flow_api.id(9266000528438793)
,p_display_seq=>11
,p_display_seq=>12
,p_column_id=>wwv_flow_api.id(9193367637668650)
,p_is_visible=>false
,p_is_frozen=>false
@ -677,7 +711,7 @@ wwv_flow_api.create_ig_report_column(
wwv_flow_api.create_ig_report_column(
p_id=>wwv_flow_api.id(9276444210438824)
,p_view_id=>wwv_flow_api.id(9266000528438793)
,p_display_seq=>12
,p_display_seq=>13
,p_column_id=>wwv_flow_api.id(9260068987429001)
,p_is_visible=>false
,p_is_frozen=>false
@ -685,7 +719,7 @@ wwv_flow_api.create_ig_report_column(
wwv_flow_api.create_ig_report_column(
p_id=>wwv_flow_api.id(9277393794438826)
,p_view_id=>wwv_flow_api.id(9266000528438793)
,p_display_seq=>13
,p_display_seq=>14
,p_column_id=>wwv_flow_api.id(9260126834429002)
,p_is_visible=>true
,p_is_frozen=>false
@ -715,6 +749,15 @@ wwv_flow_api.create_ig_report_column(
,p_is_visible=>true
,p_is_frozen=>false
);
wwv_flow_api.create_ig_report_column(
p_id=>wwv_flow_api.id(13011913824668274)
,p_view_id=>wwv_flow_api.id(9266000528438793)
,p_display_seq=>11
,p_column_id=>wwv_flow_api.id(12994588754936905)
,p_is_visible=>true
,p_is_frozen=>false
,p_width=>100
);
wwv_flow_api.create_page_plug(
p_id=>wwv_flow_api.id(12336291767960931)
,p_plug_name=>'Page Regions [GRID]'
@ -1103,6 +1146,18 @@ wwv_flow_api.create_interactive_grid(
'}',
''))
);
wwv_flow_api.component_end;
end;
/
begin
wwv_flow_api.component_begin (
p_version_yyyy_mm_dd=>'2021.04.15'
,p_release=>'21.1.6'
,p_default_workspace_id=>9014660246496943
,p_default_application_id=>770
,p_default_id_offset=>0
,p_default_owner=>'CORE'
);
wwv_flow_api.create_ig_report(
p_id=>wwv_flow_api.id(12685075256022330)
,p_interactive_grid_id=>wwv_flow_api.id(12336381739960932)
@ -1131,18 +1186,6 @@ wwv_flow_api.create_ig_report_column(
,p_is_frozen=>false
,p_width=>60
);
wwv_flow_api.component_end;
end;
/
begin
wwv_flow_api.component_begin (
p_version_yyyy_mm_dd=>'2021.04.15'
,p_release=>'21.1.6'
,p_default_workspace_id=>9014660246496943
,p_default_application_id=>770
,p_default_id_offset=>0
,p_default_owner=>'CORE'
);
wwv_flow_api.create_ig_report_column(
p_id=>wwv_flow_api.id(12685747957022334)
,p_view_id=>wwv_flow_api.id(12685246753022330)

View File

@ -7,6 +7,7 @@ CREATE TABLE navigation (
order# NUMBER(4),
is_hidden CHAR(1),
is_reset CHAR(1),
is_shared CHAR(1), -- only for CORE app
--
updated_by VARCHAR2(30),
updated_at DATE,
@ -26,7 +27,10 @@ CREATE TABLE navigation (
CHECK (is_hidden = 'Y' OR is_hidden IS NULL),
--
CONSTRAINT ch_navigation_is_reset
CHECK (is_reset = 'Y' OR is_reset IS NULL)
CHECK (is_reset = 'Y' OR is_reset IS NULL),
--
CONSTRAINT ch_navigation_is_shared
CHECK ((is_shared = 'Y' AND app_id = 770) OR is_shared IS NULL) -- CORE app_id
)
STORAGE (BUFFER_POOL KEEP);
--
@ -38,4 +42,5 @@ COMMENT ON COLUMN navigation.parent_id IS 'Parent page id for tree structur
COMMENT ON COLUMN navigation.order# IS 'Order of siblings';
COMMENT ON COLUMN navigation.is_hidden IS 'Y = dont show in menu';
COMMENT ON COLUMN navigation.is_reset IS 'Y = reset/clear all items not passed in url';
COMMENT ON COLUMN navigation.is_shared IS 'Y = show these items in other apps, only for CORE app';

89
triggers/navigation__.sql Normal file
View File

@ -0,0 +1,89 @@
CREATE OR REPLACE TRIGGER navigation__
FOR UPDATE OR INSERT OR DELETE ON navigation
COMPOUND TRIGGER
in_table_name CONSTANT user_tables.table_name%TYPE := 'NAVIGATION';
--
curr_log_id logs.log_id%TYPE;
curr_event_id log_events.log_id%TYPE;
curr_updated_by navigation.updated_by%TYPE;
curr_updated_at navigation.updated_at%TYPE;
--
rows_inserted PLS_INTEGER := 0;
rows_updated PLS_INTEGER := 0;
rows_deleted PLS_INTEGER := 0;
--
last_rowid ROWID;
BEFORE STATEMENT IS
BEGIN
curr_log_id := app.log_trigger(in_table_name);
curr_updated_by := app.get_user_id();
curr_updated_at := SYSDATE;
EXCEPTION
WHEN app.app_exception THEN
RAISE;
WHEN OTHERS THEN
app.raise_error('TRIGGER_FAILED', in_table_name);
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
IF NOT DELETING THEN
:NEW.updated_by := curr_updated_by;
:NEW.updated_at := curr_updated_at;
END IF;
EXCEPTION
WHEN app.app_exception THEN
RAISE;
WHEN OTHERS THEN
app.raise_error('TRIGGER_FAILED', in_table_name);
END BEFORE EACH ROW;
AFTER EACH ROW IS
new_json VARCHAR2(32767);
old_json VARCHAR2(32767);
BEGIN
IF INSERTING THEN
rows_inserted := rows_inserted + 1;
last_rowid := :NEW.ROWID;
ELSIF UPDATING THEN
rows_updated := rows_updated + 1;
last_rowid := :OLD.ROWID;
ELSIF DELETING THEN
rows_deleted := rows_deleted + 1;
last_rowid := :OLD.ROWID;
END IF;
EXCEPTION
WHEN app.app_exception THEN
RAISE;
WHEN OTHERS THEN
app.raise_error('TRIGGER_FAILED', in_table_name);
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
app.log_success (
in_log_id => curr_log_id,
in_rows_inserted => rows_inserted,
in_rows_updated => rows_updated,
in_rows_deleted => rows_deleted,
in_last_rowid => last_rowid
);
EXCEPTION
WHEN app.app_exception THEN
RAISE;
WHEN OTHERS THEN
app.raise_error('TRIGGER_FAILED', in_table_name);
END AFTER STATEMENT;
END;
/

View File

@ -1,15 +1,20 @@
CREATE OR REPLACE VIEW nav_overview AS
WITH x AS (
SELECT
app.get_item('$PAGE_ID') AS page_id
app.get_item('$PAGE_ID') AS filter_page_id,
app.get_page_id() AS page_id,
app.get_core_app_id() AS core_app_id,
--
COALESCE(CASE WHEN app.get_app_id() = app.get_core_app_id() THEN app.get_proxy_app_id() END, app.get_app_id()) AS app_id
FROM users u
WHERE u.user_id = app.get_user_id()
),
t AS (
SELECT
n.app_id,
n.page_id,
p.page_name,
p.page_title,
REPLACE(p.page_name, '&' || 'APP_NAME.', a.application_name) AS page_name,
REPLACE(p.page_title, '&' || 'APP_NAME.', a.application_name) AS page_title,
p.page_alias,
p.page_group,
p.authorization_scheme,
@ -17,10 +22,13 @@ t AS (
LEVEL - 1 AS depth,
CONNECT_BY_ROOT NVL(n.order#, n.page_id) AS page_root
FROM navigation n
CROSS JOIN x
LEFT JOIN apex_application_pages p
ON p.application_id = n.app_id
AND p.page_id = n.page_id
WHERE n.app_id = app.get_app_id()
LEFT JOIN apex_applications a
ON a.application_id = p.application_id
WHERE n.app_id IN (x.app_id, x.core_app_id)
CONNECT BY n.parent_id = PRIOR n.page_id
AND n.app_id = PRIOR n.app_id
START WITH n.parent_id IS NULL
@ -34,7 +42,12 @@ SELECT
t.page_alias,
--
CASE WHEN r.page_id IS NULL
THEN REPLACE(LTRIM(RPAD('-', t.depth * 4), '-'), ' ', '&' || 'nbsp; ') || app.get_page_name(in_name => t.page_name)
THEN REPLACE(LTRIM(RPAD('-', t.depth * 4), '-'), ' ', '&' || 'nbsp; ') ||
app.get_page_name (
in_app_id => n.app_id,
in_page_id => n.page_id,
in_name => t.page_name
)
END AS page_name,
--
t.page_title,
@ -42,6 +55,7 @@ SELECT
--
n.is_hidden,
n.is_reset,
n.is_shared,
--
CASE WHEN t.authorization_scheme LIKE '%MUST_NOT_BE_PUBLIC_USER%'
THEN app.get_icon('fa-check-square', 'MUST_NOT_BE_PUBLIC_USER')
@ -49,10 +63,15 @@ SELECT
END AS auth_scheme,
--
CASE WHEN n.page_id > 0 AND r.page_id IS NULL
THEN app.get_page_link(n.page_id, in_session_id => CASE WHEN n.page_id = 9999 THEN 0 END)
THEN app.get_page_link (
in_page_id => n.page_id,
in_app_id => n.app_id,
in_session_id => CASE WHEN n.page_id = 9999 THEN 0 END
)
END AS page_url,
--
'UD' AS allow_changes, -- U = update, D = delete
--
t.page_root || '.' || t.depth || '.' || NVL(n.order#, n.page_id) AS sort_order,
--
CASE
@ -61,19 +80,32 @@ SELECT
END AS action,
--
app.get_page_link (
in_page_id => app.get_page_id(),
in_app_id => n.app_id,
in_names => 'P' || TO_CHAR(app.get_page_id()) || '_REMOVE_PAGE',
in_values => TO_CHAR(n.page_id)
in_page_id => x.page_id,
in_app_id => n.app_id,
in_names => 'P' || TO_CHAR(x.page_id) || '_REMOVE_PAGE',
in_values => TO_CHAR(n.page_id)
) AS action_url
FROM navigation n
CROSS JOIN x
LEFT JOIN t
ON t.page_id = n.page_id
ON t.app_id = n.app_id
AND t.page_id = n.page_id
LEFT JOIN nav_pages_to_remove r
ON r.page_id = n.page_id
WHERE (x.page_id = n.page_id OR x.page_id IS NULL)
AND n.app_id = app.get_app_id()
ON r.page_id = n.page_id
WHERE (x.filter_page_id = n.page_id OR x.filter_page_id IS NULL)
AND (
n.app_id = x.app_id
OR (
n.app_id = x.core_app_id
AND n.is_shared = 'Y'
AND n.page_id NOT IN (
-- if page from CORE has same page number in current app, then skip it
SELECT n.page_id
FROM navigation n
WHERE n.app_id = x.app_id
)
)
)
--
UNION ALL
SELECT
@ -83,35 +115,46 @@ SELECT
n.order#,
t.page_root || ' ' || n.page_group AS page_group,
n.page_alias,
CASE WHEN n.parent_id IS NOT NULL THEN REPLACE(LTRIM(RPAD('-', 4), '-'), ' ', '&' || 'nbsp; ') END || app.get_page_name(in_name => n.page_name) AS page_name,
--
CASE WHEN n.parent_id IS NOT NULL
THEN REPLACE(LTRIM(RPAD('-', 4), '-'), ' ', '&' || 'nbsp; ')
END || app.get_page_name(in_app_id => n.app_id, in_page_id => n.page_id, in_name => n.page_name) AS page_name,
--
n.page_title,
n.css_class,
--
'Y' AS is_hidden,
'Y' AS is_reset,
NULL AS is_shared,
--
CASE WHEN n.auth_scheme LIKE '%MUST_NOT_BE_PUBLIC_USER%'
THEN app.get_icon('fa-check-square', 'MUST_NOT_BE_PUBLIC_USER')
ELSE n.auth_scheme
END AS auth_scheme,
--
app.get_page_link(n.page_id) AS page_url,
app.get_page_link (
in_page_id => n.page_id,
in_app_id => n.app_id
) AS page_url,
--
NULL AS allow_changes, -- no changes allowed
--
t.page_root || '.' || (t.depth + 1) || '.' || NVL(n.order#, n.page_id) AS sort_order,
--
app.get_icon('fa-plus-square', 'Create record in Navigation table') AS action,
--
app.get_page_link (
in_page_id => app.get_page_id(),
in_page_id => x.page_id,
in_app_id => n.app_id,
in_names => 'P' || TO_CHAR(app.get_page_id()) || '_ADD_PAGE',
in_names => 'P' || TO_CHAR(x.page_id) || '_ADD_PAGE',
in_values => TO_CHAR(n.page_id)
) AS action_url
FROM nav_pages_to_add n
CROSS JOIN x
LEFT JOIN t
ON t.page_id = n.parent_id
WHERE (x.page_id = n.page_id OR x.page_id IS NULL);
ON t.app_id = n.app_id
AND t.page_id = n.parent_id
WHERE (x.filter_page_id = n.page_id OR x.filter_page_id IS NULL);
--
COMMENT ON TABLE nav_overview IS 'Enriched navigation overview used also for menu rendering';
--

View File

@ -21,9 +21,11 @@ SELECT
THEN REGEXP_REPLACE(REPLACE(n.page_name, '&' || 'APP_USER.', APEX_ESCAPE.HTML(NVL(curr.user_name, curr.user_id))), '^(&' || 'nbsp; )+', '')
ELSE '</li></ul><ul class="EMPTY"></ul><ul><li class="HIDDEN" style="display: none;">' -- a trick to split nav menu to left and right
END AS label,
--
CASE
WHEN n.page_id > 0
THEN APEX_PAGE.GET_URL (
p_application => n.app_id,
p_page => NVL(n.page_alias, TO_CHAR(n.page_id)),
p_clear_cache => CASE WHEN n.is_reset = 'Y' THEN n.page_id END,
p_session => CASE WHEN n.page_id != 9999 THEN app.get_session_id() ELSE 0 END