From ac88add40b905f7ca264749cec79b57239d8559a Mon Sep 17 00:00:00 2001 From: mschill Date: Fri, 9 Jan 2026 09:12:00 -0500 Subject: [PATCH] C2025-043 Admin Tool - Data Check - Tool to identify and report RO's that are not used in any of the PROMS data. --- PROMS/VEPROMS User Interface/PROMSFixes.Sql | 69 ++++- .../frmBatchRefresh.Designer.cs | 272 +++++++++++------- .../VEPROMS User Interface/frmBatchRefresh.cs | 39 ++- .../frmBatchRefresh.resx | 101 +++---- .../Minimal/GeneralReports.cs | 42 +++ .../VEPROMS.CSLA.Library.csproj | 1 + .../TreeViewExtensions.cs | 115 ++++++++ .../Volian.Controls.Library.csproj | 2 + 8 files changed, 480 insertions(+), 161 deletions(-) create mode 100644 PROMS/VEPROMS.CSLA.Library/Minimal/GeneralReports.cs create mode 100644 PROMS/Volian.Controls.Library/TreeViewExtensions.cs diff --git a/PROMS/VEPROMS User Interface/PROMSFixes.Sql b/PROMS/VEPROMS User Interface/PROMSFixes.Sql index f36c64d6..2c5d71a3 100644 --- a/PROMS/VEPROMS User Interface/PROMSFixes.Sql +++ b/PROMS/VEPROMS User Interface/PROMSFixes.Sql @@ -24432,6 +24432,71 @@ ELSE PRINT 'Procedure Creation: [vesp_GetOtherActiveSessions] Error on Creation' GO +IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[vesp_GetROsNotUsed]') AND OBJECTPROPERTY(id,N'IsProcedure') = 1) + DROP PROCEDURE [vesp_GetROsNotUsed]; + +GO + +/****** Object: StoredProcedure [dbo].[vesp_GetROsNotUsed] ******/ + +-- ============================================= +-- Author: Matthew Schill +-- Create date: 1/5/2026 +-- Description: Returns ROs that are not Used in PROMS +-- ============================================= +CREATE PROCEDURE [dbo].[vesp_GetROsNotUsed] +AS +BEGIN + + DECLARE @notused table (RofstChildID int NULL, roid [varchar](50) NULL, ID int NOT NULL, ParentID int NOT NULL, dbID int NOT NULL, title varchar(max) not null) + + DECLARE @FSTs table (RofstID int primary key NOT NULL, RODbID int NOT NULL) + + INSERT INTO @FSTs + Select max(RoFSTID), RODbID from ROFsts + GROUP BY RODbID + + --insert the not used ROs + INSERT INTO @notused + SELECT RofstChild.RofstChildID, RofstChild.roid, RofstChild.ID, RofstChild.ParentID, RofstChild.dbiID, + RofstChild.title + Case When (Not RofstChild.[value] is null) Then ' (' + fstdb.dbiAP + '-' + RofstChild.appid + ')' Else '' End --Add in Accessory Page ID if it exists + FROM RofstChild + INNER JOIN RofstDatabase fstdb on fstdb.RofstID = RofstChild.RofstID and fstdb.dbiID = RofstChild.dbiID + INNER JOIN @FSTs fst on fst.RofstID = fstdb.RofstID AND RofstChild.RofstID = fst.RofstID + where + NOT EXISTS(Select 1 FROM RofstChild subchild where subChild.ParentID = RofstChild.ID) --make sure it is not a parent of something else + AND NOT EXISTS(Select 1 FROM DRoUsages where [DRoUsages].[ROID] like RofstChild.[ROID] + '%' AND fst.RODbID = DROUsages.RODbID) --not used in documents + AND NOT EXISTS(Select 1 FROM RoUsages where [RoUsages].[ROID] like RofstChild.[ROID] + '%' AND fst.RODbID = ROUsages.RODbID) --not used in regular ROs + + --insert thier parents + --if they are not already in @notused + INSERT INTO @notused + SELECT DISTINCT RofstChild.RofstChildID, RofstChild.roid, RofstChild.ID, RofstChild.ParentID, RofstChild.dbiID, RofstChild.title + FROM RofstChild + INNER JOIN @notused notusedgetparents on notusedgetparents.ParentID = RofstChild.ID AND RofstChild.dbiID = notusedgetparents.dbID + INNER JOIN @FSTs fst on RofstChild.RofstID = fst.RofstID + LEFT OUTER JOIN @notused notused on notused.RofstChildID = RofstChild.RofstChildID + WHERE notused.RofstChildID IS NULL + + --insert parent dbs + --if they are not already in @notused + INSERT INTO @notused + SELECT DISTINCT NULL, NULL, RofstDatabase.ID, RofstDatabase.ParentID, RofstDatabase.dbiID, RofstDatabase.dbiTitle + FROM RofstDatabase + INNER JOIN @FSTs fst on fst.RofstID = RofstDatabase.RofstID + + select * + FROM @notused notused + order by RofstChildID, dbID + + RETURN +END + +IF (@@Error = 0) PRINT 'Procedure Creation: [vesp_GetROsNotUsed] Succeeded' +ELSE PRINT 'Procedure Creation: [vesp_GetROsNotUsed] Error on Creation' +GO + + /* --------------------------------------------------------------------------- | ADD New Code Before this Block | @@ -24465,8 +24530,8 @@ BEGIN TRY -- Try Block DECLARE @RevDate varchar(255) DECLARE @RevDescription varchar(255) - set @RevDate = '09/16/2025 7:00 AM' - set @RevDescription = 'Added Purge Change History and Index Maintenance functions to Admin Tools' + set @RevDate = '1/5/2026 7:00 AM' + set @RevDescription = 'Added Method to get ROs that are not used in PROMS' Select cast(@RevDate as datetime) RevDate, @RevDescription RevDescription PRINT 'SQL Code Revision ' + @RevDate + ' - ' + @RevDescription diff --git a/PROMS/VEPROMS User Interface/frmBatchRefresh.Designer.cs b/PROMS/VEPROMS User Interface/frmBatchRefresh.Designer.cs index 635d8516..a3a789a3 100644 --- a/PROMS/VEPROMS User Interface/frmBatchRefresh.Designer.cs +++ b/PROMS/VEPROMS User Interface/frmBatchRefresh.Designer.cs @@ -52,6 +52,16 @@ this.expandableSplitter1 = new DevComponents.DotNetBar.ExpandableSplitter(); this.panelEx1 = new DevComponents.DotNetBar.PanelEx(); this.sideNav1 = new DevComponents.DotNetBar.Controls.SideNav(); + this.sideNavPanel5 = new DevComponents.DotNetBar.Controls.SideNavPanel(); + this.itemPanel1 = new DevComponents.DotNetBar.PanelEx(); + this.btnPurgeChange = new DevComponents.DotNetBar.ButtonX(); + this.dtePurge = new System.Windows.Forms.DateTimePicker(); + this.warningBox3 = new DevComponents.DotNetBar.Controls.WarningBox(); + this.warningBox6 = new DevComponents.DotNetBar.Controls.WarningBox(); + this.itemPanel2 = new DevComponents.DotNetBar.PanelEx(); + this.btnIndexMaint = new DevComponents.DotNetBar.ButtonX(); + this.itemPanel3 = new DevComponents.DotNetBar.PanelEx(); + this.btnROsNotUsed = new DevComponents.DotNetBar.ButtonX(); this.sideNavPanel2 = new DevComponents.DotNetBar.Controls.SideNavPanel(); this.swRefreshTblsForSrch = new DevComponents.DotNetBar.Controls.SwitchButton(); this.lblRefreshTblForSrch = new DevComponents.DotNetBar.LabelX(); @@ -75,13 +85,6 @@ this.labelX14 = new DevComponents.DotNetBar.LabelX(); this.myTVdel = new System.Windows.Forms.TreeView(); this.btnDeleteItems = new DevComponents.DotNetBar.ButtonX(); - this.sideNavPanel5 = new DevComponents.DotNetBar.Controls.SideNavPanel(); - this.btnIndexMaint = new DevComponents.DotNetBar.ButtonX(); - this.itemPanel1 = new DevComponents.DotNetBar.PanelEx(); - this.btnPurgeChange = new DevComponents.DotNetBar.ButtonX(); - this.dtePurge = new System.Windows.Forms.DateTimePicker(); - this.warningBox3 = new DevComponents.DotNetBar.Controls.WarningBox(); - this.warningBox6 = new DevComponents.DotNetBar.Controls.WarningBox(); this.sideNavPanel3 = new DevComponents.DotNetBar.Controls.SideNavPanel(); this.swCheckROLinks = new DevComponents.DotNetBar.Controls.SwitchButton(); this.labelX12 = new DevComponents.DotNetBar.LabelX(); @@ -120,10 +123,12 @@ this.pnlLater.SuspendLayout(); this.panelEx1.SuspendLayout(); this.sideNav1.SuspendLayout(); - this.sideNavPanel2.SuspendLayout(); - this.sideNavPanel4.SuspendLayout(); this.sideNavPanel5.SuspendLayout(); this.itemPanel1.SuspendLayout(); + this.itemPanel2.SuspendLayout(); + this.itemPanel3.SuspendLayout(); + this.sideNavPanel2.SuspendLayout(); + this.sideNavPanel4.SuspendLayout(); this.sideNavPanel3.SuspendLayout(); this.panelEx4.SuspendLayout(); this.SuspendLayout(); @@ -346,7 +351,7 @@ this.pnlLater.Controls.Add(this.dtpDate); this.pnlLater.Dock = System.Windows.Forms.DockStyle.Top; this.pnlLater.Enabled = false; - this.pnlLater.Location = new System.Drawing.Point(6, 23); + this.pnlLater.Location = new System.Drawing.Point(6, 25); this.pnlLater.Name = "pnlLater"; this.pnlLater.Padding = new System.Windows.Forms.Padding(6); this.pnlLater.Size = new System.Drawing.Size(279, 37); @@ -357,7 +362,7 @@ this.label5.AutoSize = true; this.label5.Location = new System.Drawing.Point(105, 15); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(18, 13); + this.label5.Size = new System.Drawing.Size(19, 15); this.label5.TabIndex = 5; this.label5.Text = "@"; // @@ -387,7 +392,7 @@ this.chkLater.Dock = System.Windows.Forms.DockStyle.Top; this.chkLater.Location = new System.Drawing.Point(6, 6); this.chkLater.Name = "chkLater"; - this.chkLater.Size = new System.Drawing.Size(279, 17); + this.chkLater.Size = new System.Drawing.Size(279, 19); this.chkLater.TabIndex = 4; this.chkLater.Text = "Process Later"; this.chkLater.UseVisualStyleBackColor = true; @@ -460,8 +465,8 @@ // sideNav1 // this.sideNav1.BackColor = System.Drawing.SystemColors.Control; - this.sideNav1.Controls.Add(this.sideNavPanel2); this.sideNav1.Controls.Add(this.sideNavPanel5); + this.sideNav1.Controls.Add(this.sideNavPanel2); this.sideNav1.Controls.Add(this.sideNavPanel4); this.sideNav1.Controls.Add(this.sideNavPanel3); this.sideNav1.Dock = System.Windows.Forms.DockStyle.Fill; @@ -482,6 +487,138 @@ this.sideNav1.TabIndex = 3; this.sideNav1.Text = "sideNav1"; // + // sideNavPanel5 + // + this.sideNavPanel5.Controls.Add(this.itemPanel1); + this.sideNavPanel5.Controls.Add(this.itemPanel2); + this.sideNavPanel5.Controls.Add(this.itemPanel3); + this.sideNavPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.sideNavPanel5.Location = new System.Drawing.Point(117, 35); + this.sideNavPanel5.MinimumSize = new System.Drawing.Size(0, 493); + this.sideNavPanel5.Name = "sideNavPanel5"; + this.sideNavPanel5.Size = new System.Drawing.Size(263, 493); + this.sideNavPanel5.TabIndex = 26; + // + // itemPanel1 + // + this.itemPanel1.Controls.Add(this.btnPurgeChange); + this.itemPanel1.Controls.Add(this.dtePurge); + this.itemPanel1.Controls.Add(this.warningBox3); + this.itemPanel1.Controls.Add(this.warningBox6); + this.itemPanel1.DisabledBackColor = System.Drawing.Color.Empty; + this.itemPanel1.Location = new System.Drawing.Point(0, -2); + this.itemPanel1.Name = "itemPanel1"; + this.itemPanel1.Size = new System.Drawing.Size(267, 148); + this.itemPanel1.Style.Border = DevComponents.DotNetBar.eBorderType.DoubleLine; + this.itemPanel1.Style.BorderColor.Color = System.Drawing.Color.DarkGray; + this.itemPanel1.TabIndex = 0; + // + // btnPurgeChange + // + this.btnPurgeChange.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton; + this.btnPurgeChange.Checked = true; + this.btnPurgeChange.ColorTable = DevComponents.DotNetBar.eButtonColor.OrangeWithBackground; + this.btnPurgeChange.Location = new System.Drawing.Point(18, 32); + this.btnPurgeChange.Name = "btnPurgeChange"; + this.btnPurgeChange.Size = new System.Drawing.Size(227, 23); + this.btnPurgeChange.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled; + this.btnPurgeChange.TabIndex = 1; + this.btnPurgeChange.Text = "Purge Change History"; + this.btnPurgeChange.Tooltip = resources.GetString("btnPurgeChange.Tooltip"); + this.btnPurgeChange.Click += new System.EventHandler(this.btnPurgeChange_Click); + // + // dtePurge + // + this.dtePurge.Format = System.Windows.Forms.DateTimePickerFormat.Short; + this.dtePurge.Location = new System.Drawing.Point(92, 7); + this.dtePurge.Name = "dtePurge"; + this.dtePurge.Size = new System.Drawing.Size(87, 20); + this.dtePurge.TabIndex = 0; + // + // warningBox3 + // + this.warningBox3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(196)))), ((int)(((byte)(219)))), ((int)(((byte)(249))))); + this.warningBox3.CloseButtonVisible = false; + this.warningBox3.Image = ((System.Drawing.Image)(resources.GetObject("warningBox3.Image"))); + this.warningBox3.Location = new System.Drawing.Point(1, 61); + this.warningBox3.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.warningBox3.Name = "warningBox3"; + this.warningBox3.OptionsButtonVisible = false; + this.warningBox3.Size = new System.Drawing.Size(264, 32); + this.warningBox3.TabIndex = 32; + this.warningBox3.Text = "NOTE These tools can take a long time to run"; + // + // warningBox6 + // + this.warningBox6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(196)))), ((int)(((byte)(219)))), ((int)(((byte)(249))))); + this.warningBox6.CloseButtonVisible = false; + this.warningBox6.Image = ((System.Drawing.Image)(resources.GetObject("warningBox6.Image"))); + this.warningBox6.Location = new System.Drawing.Point(1, 97); + this.warningBox6.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.warningBox6.Name = "warningBox6"; + this.warningBox6.OptionsButtonVisible = false; + this.warningBox6.Size = new System.Drawing.Size(264, 43); + this.warningBox6.TabIndex = 31; + this.warningBox6.Text = " Be sure there is a current backup of the \r\n database prior to running these func" + + "tions"; + // + // itemPanel2 + // + this.itemPanel2.Controls.Add(this.btnIndexMaint); + this.itemPanel2.DisabledBackColor = System.Drawing.Color.Empty; + this.itemPanel2.Location = new System.Drawing.Point(0, 145); + this.itemPanel2.Name = "itemPanel2"; + this.itemPanel2.Size = new System.Drawing.Size(267, 73); + this.itemPanel2.Style.BackgroundImagePosition = DevComponents.DotNetBar.eBackgroundImagePosition.Tile; + this.itemPanel2.Style.Border = DevComponents.DotNetBar.eBorderType.DoubleLine; + this.itemPanel2.Style.BorderColor.Color = System.Drawing.Color.DarkGray; + this.itemPanel2.Style.ForeColor.ColorSchemePart = DevComponents.DotNetBar.eColorSchemePart.PanelText; + this.itemPanel2.Style.GradientAngle = 90; + this.itemPanel2.TabIndex = 8; + // + // btnIndexMaint + // + this.btnIndexMaint.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton; + this.btnIndexMaint.Checked = true; + this.btnIndexMaint.ColorTable = DevComponents.DotNetBar.eButtonColor.OrangeWithBackground; + this.btnIndexMaint.Location = new System.Drawing.Point(19, 24); + this.btnIndexMaint.Name = "btnIndexMaint"; + this.btnIndexMaint.Size = new System.Drawing.Size(227, 23); + this.btnIndexMaint.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled; + this.btnIndexMaint.TabIndex = 4; + this.btnIndexMaint.Text = "Perform Index Maintenance"; + this.btnIndexMaint.Tooltip = resources.GetString("btnIndexMaint.Tooltip"); + this.btnIndexMaint.Click += new System.EventHandler(this.btnIndexMaint_Click); + // + // itemPanel3 + // + this.itemPanel3.Controls.Add(this.btnROsNotUsed); + this.itemPanel3.DisabledBackColor = System.Drawing.Color.Empty; + this.itemPanel3.Location = new System.Drawing.Point(0, 218); + this.itemPanel3.Name = "itemPanel3"; + this.itemPanel3.Size = new System.Drawing.Size(267, 70); + this.itemPanel3.Style.BackgroundImagePosition = DevComponents.DotNetBar.eBackgroundImagePosition.Tile; + this.itemPanel3.Style.Border = DevComponents.DotNetBar.eBorderType.DoubleLine; + this.itemPanel3.Style.BorderColor.Color = System.Drawing.Color.DarkGray; + this.itemPanel3.Style.ForeColor.ColorSchemePart = DevComponents.DotNetBar.eColorSchemePart.PanelText; + this.itemPanel3.Style.GradientAngle = 90; + this.itemPanel3.TabIndex = 12; + // + // btnROsNotUsed + // + this.btnROsNotUsed.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton; + this.btnROsNotUsed.Checked = true; + this.btnROsNotUsed.ColorTable = DevComponents.DotNetBar.eButtonColor.OrangeWithBackground; + this.btnROsNotUsed.Location = new System.Drawing.Point(19, 22); + this.btnROsNotUsed.Name = "btnROsNotUsed"; + this.btnROsNotUsed.Size = new System.Drawing.Size(227, 26); + this.btnROsNotUsed.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled; + this.superTooltip1.SetSuperTooltip(this.btnROsNotUsed, new DevComponents.DotNetBar.SuperTooltipInfo("ROs Not Used Snapshot", "", "This will Generate an image detailing ROs that exist but are not currently utiliz" + + "ed in any steps in PROMS.", null, null, DevComponents.DotNetBar.eTooltipColor.Gray)); + this.btnROsNotUsed.TabIndex = 2; + this.btnROsNotUsed.Text = "Generate Snapshot of ROs Not Used"; + this.btnROsNotUsed.Click += new System.EventHandler(this.btnROsNotUsed_Click); + // // sideNavPanel2 // this.sideNavPanel2.Controls.Add(this.swRefreshTblsForSrch); @@ -504,6 +641,7 @@ this.sideNavPanel2.Name = "sideNavPanel2"; this.sideNavPanel2.Size = new System.Drawing.Size(268, 493); this.sideNavPanel2.TabIndex = 6; + this.sideNavPanel2.Visible = false; // // swRefreshTblsForSrch // @@ -543,7 +681,7 @@ this.warningBox4.CloseButtonVisible = false; this.warningBox4.Image = ((System.Drawing.Image)(resources.GetObject("warningBox4.Image"))); this.warningBox4.Location = new System.Drawing.Point(12, 264); - this.warningBox4.Margin = new System.Windows.Forms.Padding(4); + this.warningBox4.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.warningBox4.Name = "warningBox4"; this.warningBox4.OptionsButtonVisible = false; this.warningBox4.Size = new System.Drawing.Size(264, 32); @@ -556,7 +694,7 @@ this.warningBox2.CloseButtonVisible = false; this.warningBox2.Image = ((System.Drawing.Image)(resources.GetObject("warningBox2.Image"))); this.warningBox2.Location = new System.Drawing.Point(12, 302); - this.warningBox2.Margin = new System.Windows.Forms.Padding(4); + this.warningBox2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.warningBox2.Name = "warningBox2"; this.warningBox2.OptionsButtonVisible = false; this.warningBox2.Size = new System.Drawing.Size(264, 43); @@ -834,95 +972,6 @@ this.btnDeleteItems.TabIndex = 35; this.btnDeleteItems.Text = "Process Deletions"; this.btnDeleteItems.Click += new System.EventHandler(this.btnDeleteItems_Click); - // - // sideNavPanel5 - // - this.sideNavPanel5.Controls.Add(this.btnIndexMaint); - this.sideNavPanel5.Controls.Add(this.itemPanel1); - this.sideNavPanel5.Dock = System.Windows.Forms.DockStyle.Fill; - this.sideNavPanel5.Location = new System.Drawing.Point(112, 31); - this.sideNavPanel5.MinimumSize = new System.Drawing.Size(0, 493); - this.sideNavPanel5.Name = "sideNavPanel5"; - this.sideNavPanel5.Size = new System.Drawing.Size(268, 493); - this.sideNavPanel5.TabIndex = 26; - this.sideNavPanel5.Visible = false; - // - // btnIndexMaint - // - this.btnIndexMaint.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton; - this.btnIndexMaint.Checked = true; - this.btnIndexMaint.ColorTable = DevComponents.DotNetBar.eButtonColor.OrangeWithBackground; - this.btnIndexMaint.Location = new System.Drawing.Point(20, 152); - this.btnIndexMaint.Name = "btnIndexMaint"; - this.btnIndexMaint.Size = new System.Drawing.Size(227, 23); - this.btnIndexMaint.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled; - this.btnIndexMaint.TabIndex = 4; - this.btnIndexMaint.Text = "Perform Index Maintenance"; - this.btnIndexMaint.Tooltip = resources.GetString("btnIndexMaint.Tooltip"); - this.btnIndexMaint.Click += new System.EventHandler(this.btnIndexMaint_Click); - // - // itemPanel1 - // - this.itemPanel1.Controls.Add(this.btnPurgeChange); - this.itemPanel1.Controls.Add(this.dtePurge); - this.itemPanel1.Controls.Add(this.warningBox3); - this.itemPanel1.Controls.Add(this.warningBox6); - this.itemPanel1.DisabledBackColor = System.Drawing.Color.Empty; - this.itemPanel1.Location = new System.Drawing.Point(0, -2); - this.itemPanel1.Name = "itemPanel1"; - this.itemPanel1.Size = new System.Drawing.Size(267, 148); - this.itemPanel1.Style.Border = DevComponents.DotNetBar.eBorderType.DoubleLine; - this.itemPanel1.Style.BorderColor.Color = System.Drawing.Color.DarkGray; - this.itemPanel1.TabIndex = 0; - // - // btnPurgeChange - // - this.btnPurgeChange.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton; - this.btnPurgeChange.Checked = true; - this.btnPurgeChange.ColorTable = DevComponents.DotNetBar.eButtonColor.OrangeWithBackground; - this.btnPurgeChange.Location = new System.Drawing.Point(18, 32); - this.btnPurgeChange.Name = "btnPurgeChange"; - this.btnPurgeChange.Size = new System.Drawing.Size(227, 23); - this.btnPurgeChange.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled; - this.btnPurgeChange.TabIndex = 1; - this.btnPurgeChange.Text = "Purge Change History"; - this.btnPurgeChange.Tooltip = resources.GetString("btnPurgeChange.Tooltip"); - this.btnPurgeChange.Click += new System.EventHandler(this.btnPurgeChange_Click); - // - // dtePurge - // - this.dtePurge.Format = System.Windows.Forms.DateTimePickerFormat.Short; - this.dtePurge.Location = new System.Drawing.Point(92, 7); - this.dtePurge.Name = "dtePurge"; - this.dtePurge.Size = new System.Drawing.Size(87, 20); - this.dtePurge.TabIndex = 0; - // - // warningBox3 - // - this.warningBox3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(196)))), ((int)(((byte)(219)))), ((int)(((byte)(249))))); - this.warningBox3.CloseButtonVisible = false; - this.warningBox3.Image = ((System.Drawing.Image)(resources.GetObject("warningBox3.Image"))); - this.warningBox3.Location = new System.Drawing.Point(1, 61); - this.warningBox3.Margin = new System.Windows.Forms.Padding(4); - this.warningBox3.Name = "warningBox3"; - this.warningBox3.OptionsButtonVisible = false; - this.warningBox3.Size = new System.Drawing.Size(264, 32); - this.warningBox3.TabIndex = 32; - this.warningBox3.Text = "NOTE These tools can take a long time to run"; - // - // warningBox6 - // - this.warningBox6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(196)))), ((int)(((byte)(219)))), ((int)(((byte)(249))))); - this.warningBox6.CloseButtonVisible = false; - this.warningBox6.Image = ((System.Drawing.Image)(resources.GetObject("warningBox6.Image"))); - this.warningBox6.Location = new System.Drawing.Point(1, 97); - this.warningBox6.Margin = new System.Windows.Forms.Padding(4); - this.warningBox6.Name = "warningBox6"; - this.warningBox6.OptionsButtonVisible = false; - this.warningBox6.Size = new System.Drawing.Size(264, 43); - this.warningBox6.TabIndex = 31; - this.warningBox6.Text = " Be sure there is a current backup of the \r\n database prior to running these func" + - "tions"; // // sideNavPanel3 // @@ -981,7 +1030,7 @@ this.warningBox5.CloseButtonVisible = false; this.warningBox5.Image = ((System.Drawing.Image)(resources.GetObject("warningBox5.Image"))); this.warningBox5.Location = new System.Drawing.Point(17, 145); - this.warningBox5.Margin = new System.Windows.Forms.Padding(4); + this.warningBox5.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.warningBox5.Name = "warningBox5"; this.warningBox5.OptionsButtonVisible = false; this.warningBox5.Size = new System.Drawing.Size(262, 32); @@ -1065,7 +1114,7 @@ this.warningBox1.CloseButtonVisible = false; this.warningBox1.Image = ((System.Drawing.Image)(resources.GetObject("warningBox1.Image"))); this.warningBox1.Location = new System.Drawing.Point(17, 181); - this.warningBox1.Margin = new System.Windows.Forms.Padding(4); + this.warningBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.warningBox1.Name = "warningBox1"; this.warningBox1.OptionsButtonVisible = false; this.warningBox1.Size = new System.Drawing.Size(262, 43); @@ -1108,7 +1157,6 @@ // // sideNavItmRepair // - this.sideNavItmRepair.Checked = true; this.sideNavItmRepair.Name = "sideNavItmRepair"; this.sideNavItmRepair.Panel = this.sideNavPanel2; this.sideNavItmRepair.Symbol = ""; @@ -1125,6 +1173,7 @@ // // sideNavItmMaint // + this.sideNavItmMaint.Checked = true; this.sideNavItmMaint.Name = "sideNavItmMaint"; this.sideNavItmMaint.Panel = this.sideNavPanel5; this.sideNavItmMaint.Symbol = "58154"; @@ -1271,10 +1320,12 @@ this.panelEx1.ResumeLayout(false); this.sideNav1.ResumeLayout(false); this.sideNav1.PerformLayout(); - this.sideNavPanel2.ResumeLayout(false); - this.sideNavPanel4.ResumeLayout(false); this.sideNavPanel5.ResumeLayout(false); this.itemPanel1.ResumeLayout(false); + this.itemPanel2.ResumeLayout(false); + this.itemPanel3.ResumeLayout(false); + this.sideNavPanel2.ResumeLayout(false); + this.sideNavPanel4.ResumeLayout(false); this.sideNavPanel3.ResumeLayout(false); this.panelEx4.ResumeLayout(false); this.ResumeLayout(false); @@ -1363,6 +1414,9 @@ private DevComponents.DotNetBar.Controls.WarningBox warningBox3; private DevComponents.DotNetBar.Controls.WarningBox warningBox6; private DevComponents.DotNetBar.ButtonX btnIndexMaint; + private DevComponents.DotNetBar.PanelEx itemPanel2; + private DevComponents.DotNetBar.PanelEx itemPanel3; + private DevComponents.DotNetBar.ButtonX btnROsNotUsed; } } diff --git a/PROMS/VEPROMS User Interface/frmBatchRefresh.cs b/PROMS/VEPROMS User Interface/frmBatchRefresh.cs index fe893ad7..f5d38a7d 100644 --- a/PROMS/VEPROMS User Interface/frmBatchRefresh.cs +++ b/PROMS/VEPROMS User Interface/frmBatchRefresh.cs @@ -1778,7 +1778,44 @@ namespace VEPROMS return true; } - } + //CSM - C2025-043 report RO's that are not used in any of the PROMS data. + private void btnROsNotUsed_Click(object sender, EventArgs e) + { + //Get the path to save the Image to + SaveFileDialog sfd = new SaveFileDialog(); + sfd.DefaultExt = "bmp"; + sfd.AddExtension = true; + sfd.Filter = "Image Files (*.bmp)|*.bmp"; + sfd.FileName = string.Format("ROsNotUsed_{0}", DateTime.Now.ToString("yyyyMMdd_HHmm")); + sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\VEPROMS"; + DialogResult dr = sfd.ShowDialog(); + + if (dr == DialogResult.OK) + { + //Initial messaging + string statmsg = "Generating Snapshot (this may take a few minutes to complete)..."; + InitialProgressBarMessage = statmsg; + txtResults.AppendText(statmsg); + txtResults.AppendText(Environment.NewLine); + + //Generate the data for ROs Not Used and save it to a TreeView + TreeView tv = TreeViewExtensions.GetROTree(GeneralReports.GetROsNotUsedInPROMS(), true); + //Output the TreeView as an Image + if (tv.Nodes.Count != 0) + tv.SaveTreeViewAsImage(sfd.FileName); + + //Give Messaging demonstrating finished and open file if requested + statmsg = "Finished Generating Snapshot of ROs Not Used."; + FinalProgressBarMessage = statmsg; + txtResults.AppendText(statmsg); + txtResults.AppendText(Environment.NewLine); + if (tv.Nodes.Count != 0 && MessageBox.Show($"{statmsg}\r\n\r\nDo you wish to open the snapshot now?", "ROs Not Used", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) + System.Diagnostics.Process.Start(sfd.FileName); + else if (tv.Nodes.Count == 0) + MessageBox.Show("All ROs are currently in use.", "ROs Not Used", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } } diff --git a/PROMS/VEPROMS User Interface/frmBatchRefresh.resx b/PROMS/VEPROMS User Interface/frmBatchRefresh.resx index d7589931..9c07f025 100644 --- a/PROMS/VEPROMS User Interface/frmBatchRefresh.resx +++ b/PROMS/VEPROMS User Interface/frmBatchRefresh.resx @@ -117,6 +117,57 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + This will perform Index Maintenance to realign indexes to optimize performance. +This function will cause no change to data or records in PROMS. +It should however be performed when other users are not in PROMS, as it could +cause slowdown or errors for other users while it is running. + + + 17, 17 + + + Purges all audit information and change history older than the above date. +It is recommended that you perform a database backup before performing this action. +Note after purging the information, this will automatically perform the Index +Maintenance function to realign indexes with the cut down audit data. +Only Full PROMS Administrator Users can perform this action. + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAp5JREFUOE+F + k11Ik1Ecxv9zouJ2E4TWnR8V5tAppJmYsLnNlaLTxAoiKIQiibpYSmEEmSSa0IVGISMUw7rpE+yiQiuk + /IhROssPyjanpL4udeq29z3nCdcH+Wb1g+fq/zzP+R8Oh+gvPK4kNWujp1IrPek8S5Hy+X9hbXSN9aVC + eq1FwEYN8vk/mWqiDPZwI+NOHbhLj8CdDaK7npLlvnWpO0AKqZV62YgO/GMquDMN0rAevkbqlHvXZdlG + h6Rn8eATu4GJncB0Fvh8HnwPYuGpJ4vcvwZbGYWJrcpPzGXG8ngGtsZFQJOggrS0B9J0MbwNIR9uHqRQ + ee4XPhuVSy814IIB/lk9QkIIanUomFgIzkux0qHB/CUqk+eCtB2jCLEl1M1mLcBSLthKHlQqJaKjw8FZ + Mbi/ENKXEizUKD/f2k9h8jz5mumk2K0F9xUAUgE4K0JUVDji4yLBvflgMyYwlxFL9zSYq6ITa8I3DlNY + wKZ0soVSgFkAXgwuFSEmJhJJiWqwCR3YSCbY2x0QB4zwnFc6W4p+22KxiY4EXiQF74kf6/L5vdi+TYV0 + rRpsMB2sPxWsRwvpTTq87QmYOUNHg+HqQlL4ryscbK4UPGD5vu60CWw8G7evbkN7bSykXm0w/FMBew6E + CsXQFQMpaLKezP6OLeDL+8AFM5hLBzaciennKcFXUCgI7o7ENQWSfRcWmmPgPEW5tNJIj8QxM9hkDthY + FthAGlh/SvAPXC7fjOrjmyC+Sl5TsCpfdzYEK92llUbllDiaD3HEDPG9CaLDCGnI9IdEhwnioBHiOwMC + dj38fYbVglHy1FGJt57uL9ZS10IN9cxfJPvXCzTgqSKH5xwNzVXSkFBBDsFKA4KV7IKVegQrda2e7j5N + ud8AKwnMnBpmYFAAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAp5JREFUOE+F + k11Ik1Ecxv9zouJ2E4TWnR8V5tAppJmYsLnNlaLTxAoiKIQiibpYSmEEmSSa0IVGISMUw7rpE+yiQiuk + /IhROssPyjanpL4udeq29z3nCdcH+Wb1g+fq/zzP+R8Oh+gvPK4kNWujp1IrPek8S5Hy+X9hbXSN9aVC + eq1FwEYN8vk/mWqiDPZwI+NOHbhLj8CdDaK7npLlvnWpO0AKqZV62YgO/GMquDMN0rAevkbqlHvXZdlG + h6Rn8eATu4GJncB0Fvh8HnwPYuGpJ4vcvwZbGYWJrcpPzGXG8ngGtsZFQJOggrS0B9J0MbwNIR9uHqRQ + ee4XPhuVSy814IIB/lk9QkIIanUomFgIzkux0qHB/CUqk+eCtB2jCLEl1M1mLcBSLthKHlQqJaKjw8FZ + Mbi/ENKXEizUKD/f2k9h8jz5mumk2K0F9xUAUgE4K0JUVDji4yLBvflgMyYwlxFL9zSYq6ITa8I3DlNY + wKZ0soVSgFkAXgwuFSEmJhJJiWqwCR3YSCbY2x0QB4zwnFc6W4p+22KxiY4EXiQF74kf6/L5vdi+TYV0 + rRpsMB2sPxWsRwvpTTq87QmYOUNHg+HqQlL4ryscbK4UPGD5vu60CWw8G7evbkN7bSykXm0w/FMBew6E + CsXQFQMpaLKezP6OLeDL+8AFM5hLBzaciennKcFXUCgI7o7ENQWSfRcWmmPgPEW5tNJIj8QxM9hkDthY + FthAGlh/SvAPXC7fjOrjmyC+Sl5TsCpfdzYEK92llUbllDiaD3HEDPG9CaLDCGnI9IdEhwnioBHiOwMC + dj38fYbVglHy1FGJt57uL9ZS10IN9cxfJPvXCzTgqSKH5xwNzVXSkFBBDsFKA4KV7IKVegQrda2e7j5N + ud8AKwnMnBpmYFAAAAAASUVORK5CYII= + + 17, 17 @@ -132,7 +183,6 @@ This function will remove all of the saved attachment PDFS stored in the databas This function will remove all of the saved attachment PDFS stored in the database (not the PDFs of the entire procedure that you had previous printed). This will force PROMS to regenerate (and save) the word attachment PDFs the next time the procedure is printed. - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAp5JREFUOE+F @@ -216,12 +266,6 @@ Should an item become orphaned (disconnected) from the rest of the data, it will Should an item become orphaned (disconnected) from the rest of the data, it will no longer be accessible. This tool removes any orphaned items from the database. - - - This will perform Index Maintenance to realign indexes to optimize performance. -This function will cause no change to data or records in PROMS. -It should however be performed when other users are not in PROMS, as it could -cause slowdown or errors for other users while it is running. This allows the user to remove folders and sub folders as well as their contents. @@ -261,47 +305,6 @@ If more than one working draft is selected, it is recommended that this be perfo Click on the on/off switches to turn on/off each tool. Note that only one of these tools can be run at a time. - - - Purges all audit information and change history older than the above date. -It is recommended that you perform a database backup before performing this action. -Note after purging the information, this will automatically perform the Index -Maintenance function to realign indexes with the cut down audit data. -Only Full PROMS Administrator Users can perform this action. - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAp5JREFUOE+F - k11Ik1Ecxv9zouJ2E4TWnR8V5tAppJmYsLnNlaLTxAoiKIQiibpYSmEEmSSa0IVGISMUw7rpE+yiQiuk - /IhROssPyjanpL4udeq29z3nCdcH+Wb1g+fq/zzP+R8Oh+gvPK4kNWujp1IrPek8S5Hy+X9hbXSN9aVC - eq1FwEYN8vk/mWqiDPZwI+NOHbhLj8CdDaK7npLlvnWpO0AKqZV62YgO/GMquDMN0rAevkbqlHvXZdlG - h6Rn8eATu4GJncB0Fvh8HnwPYuGpJ4vcvwZbGYWJrcpPzGXG8ngGtsZFQJOggrS0B9J0MbwNIR9uHqRQ - ee4XPhuVSy814IIB/lk9QkIIanUomFgIzkux0qHB/CUqk+eCtB2jCLEl1M1mLcBSLthKHlQqJaKjw8FZ - Mbi/ENKXEizUKD/f2k9h8jz5mumk2K0F9xUAUgE4K0JUVDji4yLBvflgMyYwlxFL9zSYq6ITa8I3DlNY - wKZ0soVSgFkAXgwuFSEmJhJJiWqwCR3YSCbY2x0QB4zwnFc6W4p+22KxiY4EXiQF74kf6/L5vdi+TYV0 - rRpsMB2sPxWsRwvpTTq87QmYOUNHg+HqQlL4ryscbK4UPGD5vu60CWw8G7evbkN7bSykXm0w/FMBew6E - CsXQFQMpaLKezP6OLeDL+8AFM5hLBzaciennKcFXUCgI7o7ENQWSfRcWmmPgPEW5tNJIj8QxM9hkDthY - FthAGlh/SvAPXC7fjOrjmyC+Sl5TsCpfdzYEK92llUbllDiaD3HEDPG9CaLDCGnI9IdEhwnioBHiOwMC - dj38fYbVglHy1FGJt57uL9ZS10IN9cxfJPvXCzTgqSKH5xwNzVXSkFBBDsFKA4KV7IKVegQrda2e7j5N - ud8AKwnMnBpmYFAAAAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAp5JREFUOE+F - k11Ik1Ecxv9zouJ2E4TWnR8V5tAppJmYsLnNlaLTxAoiKIQiibpYSmEEmSSa0IVGISMUw7rpE+yiQiuk - /IhROssPyjanpL4udeq29z3nCdcH+Wb1g+fq/zzP+R8Oh+gvPK4kNWujp1IrPek8S5Hy+X9hbXSN9aVC - eq1FwEYN8vk/mWqiDPZwI+NOHbhLj8CdDaK7npLlvnWpO0AKqZV62YgO/GMquDMN0rAevkbqlHvXZdlG - h6Rn8eATu4GJncB0Fvh8HnwPYuGpJ4vcvwZbGYWJrcpPzGXG8ngGtsZFQJOggrS0B9J0MbwNIR9uHqRQ - ee4XPhuVSy814IIB/lk9QkIIanUomFgIzkux0qHB/CUqk+eCtB2jCLEl1M1mLcBSLthKHlQqJaKjw8FZ - Mbi/ENKXEizUKD/f2k9h8jz5mumk2K0F9xUAUgE4K0JUVDji4yLBvflgMyYwlxFL9zSYq6ITa8I3DlNY - wKZ0soVSgFkAXgwuFSEmJhJJiWqwCR3YSCbY2x0QB4zwnFc6W4p+22KxiY4EXiQF74kf6/L5vdi+TYV0 - rRpsMB2sPxWsRwvpTTq87QmYOUNHg+HqQlL4ryscbK4UPGD5vu60CWw8G7evbkN7bSykXm0w/FMBew6E - CsXQFQMpaLKezP6OLeDL+8AFM5hLBzaciennKcFXUCgI7o7ENQWSfRcWmmPgPEW5tNJIj8QxM9hkDthY - FthAGlh/SvAPXC7fjOrjmyC+Sl5TsCpfdzYEK92llUbllDiaD3HEDPG9CaLDCGnI9IdEhwnioBHiOwMC - dj38fYbVglHy1FGJt57uL9ZS10IN9cxfJPvXCzTgqSKH5xwNzVXSkFBBDsFKA4KV7IKVegQrda2e7j5N - ud8AKwnMnBpmYFAAAAAASUVORK5CYII= - This allows the user to check referenced objects links in procedure step data for multiple working drafts in a batch mode. @@ -389,6 +392,6 @@ If more than one procedure is selected, it is recommended that this be performed - 137 + 25 \ No newline at end of file diff --git a/PROMS/VEPROMS.CSLA.Library/Minimal/GeneralReports.cs b/PROMS/VEPROMS.CSLA.Library/Minimal/GeneralReports.cs new file mode 100644 index 00000000..87c08200 --- /dev/null +++ b/PROMS/VEPROMS.CSLA.Library/Minimal/GeneralReports.cs @@ -0,0 +1,42 @@ +using System; +using Csla.Data; +using System.Data; +using System.Data.SqlClient; + +//CSM - C2025-043 - Minimal Class for General Reports +namespace VEPROMS.CSLA.Library +{ + public static class GeneralReports + { + + #region Get General Reports + //CSM - C2025-043 report RO's that are not used in any of the PROMS data. + public static DataTable GetROsNotUsedInPROMS() + { + try + { + using (SqlConnection cn = Database.VEPROMS_SqlConnection) + { + using (SqlCommand cm = cn.CreateCommand()) + { + cm.CommandType = CommandType.StoredProcedure; + cm.CommandText = "vesp_GetROsNotUsed"; + cm.CommandTimeout = Database.DefaultTimeout; + using (SqlDataAdapter da = new SqlDataAdapter(cm)) + { + DataTable dt = new DataTable(); + da.Fill(dt); + return dt; + } + } + } + } + catch (Exception ex) + { + throw new DbCslaException("Error in GetROsNotUsedInPROMS Report: retrieving data failed", ex); + } + } + #endregion + + } +} diff --git a/PROMS/VEPROMS.CSLA.Library/VEPROMS.CSLA.Library.csproj b/PROMS/VEPROMS.CSLA.Library/VEPROMS.CSLA.Library.csproj index 24da5a1b..b25089b2 100644 --- a/PROMS/VEPROMS.CSLA.Library/VEPROMS.CSLA.Library.csproj +++ b/PROMS/VEPROMS.CSLA.Library/VEPROMS.CSLA.Library.csproj @@ -390,6 +390,7 @@ + diff --git a/PROMS/Volian.Controls.Library/TreeViewExtensions.cs b/PROMS/Volian.Controls.Library/TreeViewExtensions.cs new file mode 100644 index 00000000..bd2e6112 --- /dev/null +++ b/PROMS/Volian.Controls.Library/TreeViewExtensions.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Drawing; +using System.Windows.Forms; +using System.Data; + +namespace Volian.Controls.Library +{ + //CSM - C2025-043 report RO's that are not used in any of the PROMS data. + // extend the TreeView class with a couple added functions + // to allow support for what is needed for ROs + public static class TreeViewExtensions + { + #region public functions + //Returns a ROTreeView based on the data in the datatable dt + // builds tree based on the following: + // ParentID = 0 is top level + // links (defined parent) based on same dbID and ID = ParentID + // nodes will have the text of the title + public static TreeView GetROTree(DataTable dt, bool isExpanded = false) + { + TreeView tv = new TreeView(); + + var tempnodes = GetTreeNodes( + dt.AsEnumerable(), + (r) => r.Field("ParentID") == 0, //top level of tree + (r, s) => s.Where(x => r["ID"].Equals(x["ParentID"]) && r["dbID"].Equals(x["dbID"])), //how to match parents and children + (r) => new TreeNode { Text = r.Field("title") } //what to display in the tree + ); + tv.Nodes.AddRange(tempnodes.ToArray()); + + //if set to expand, sets the height to the combined height of all nodes + 20 + //so will show whole tree + if (isExpanded) + { + tv.ExpandAll(); + tv.SetTreeViewHeighttoFull(); + tv.Width = 1200; + } + + //sorts the tree in alphabetical order to match the way the tree is sorted in the RO Editor + tv.Sorted = true; + + return tv; + } + + //Saves the Tree to an Image at the specified path + public static void SaveTreeViewAsImage(this TreeView tv, string filePath) + { + // Create a Bitmap with the size of the TreeView + Bitmap bitmap = new Bitmap(tv.Width, tv.Height); + // Draw the TreeView onto the Bitmap + tv.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height)); + // Save the Bitmap as an image file + bitmap.Save(filePath, System.Drawing.Imaging.ImageFormat.Png); + } + #endregion + + #region height functions + //This is a function to calculate and set the TreeView Height based + //on the height of all sub nodes + 20 + public static void SetTreeViewHeighttoFull(this TreeView tv) + { + int totalHeight = 0; + foreach (TreeNode node in tv.Nodes) + { + totalHeight += GetNodeHeight(node); + } + tv.Height = totalHeight + 20; + } + + //This function recursively adds the height of sub nodes to the running total + private static int GetNodeHeight(TreeNode node) + { + int curheight = node.Bounds.Height; + foreach (TreeNode child in node.Nodes) + { + curheight += GetNodeHeight(child); + } + return curheight; + } + #endregion + + #region generic private tree structure functions + //This is a Generic Function to help build the Tree Structure + private static IEnumerable GetTreeNodes( + IEnumerable source, + Func isRoot, + Func, IEnumerable> getChilds, + Func getItem) + { + IEnumerable roots = source.Where(x => isRoot(x)); + foreach (T root in roots) + yield return ConvertEntityToTreeNode(root, source, getChilds, getItem); ; + } + + //This is a Generic Function to help build the Tree Structure + private static TreeNode ConvertEntityToTreeNode( + T entity, + IEnumerable source, + Func, IEnumerable> getChilds, + Func getItem) + { + TreeNode node = getItem(entity); + var childs = getChilds(entity, source); + foreach (T child in childs) + node.Nodes.Add(ConvertEntityToTreeNode(child, source, getChilds, getItem)); + return node; + } + #endregion + + } + +} diff --git a/PROMS/Volian.Controls.Library/Volian.Controls.Library.csproj b/PROMS/Volian.Controls.Library/Volian.Controls.Library.csproj index 21fb8341..c4f41e44 100644 --- a/PROMS/Volian.Controls.Library/Volian.Controls.Library.csproj +++ b/PROMS/Volian.Controls.Library/Volian.Controls.Library.csproj @@ -118,6 +118,7 @@ ..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll + @@ -295,6 +296,7 @@ True Settings.settings + UserControl