33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 */
55
6+ import * as vscode from "vscode" ;
7+ import * as fs from "fs" ;
8+ import * as yaml from "yaml" ;
69import path from "path" ;
710import os from "os" ;
11+ import { traceError , traceInfo } from "./TelemetryHelper" ;
12+ import { Constants } from "./Constants" ;
13+ import { IOtherSiteInfo , IWebsiteDetails , WebsiteYaml } from "../../../common/services/Interfaces" ;
14+ import PacContext from "../../pac/PacContext" ;
15+ import ArtemisContext from "../../ArtemisContext" ;
16+ import { getActiveWebsites , getAllWebsites } from "../../../common/utilities/WebsiteUtil" ;
17+ import { ServiceEndpointCategory } from "../../../common/services/Constants" ;
18+ import { getWebsiteRecordId , getWebsiteYamlPath , hasWebsiteYaml } from "../../../common/utilities/WorkspaceInfoFinderUtil" ;
19+ import { POWERPAGES_SITE_FOLDER , UTF8_ENCODING } from "../../../common/constants" ;
820
21+ export function createKnownSiteIdsSet (
22+ activeSites : IWebsiteDetails [ ] | undefined ,
23+ inactiveSites : IWebsiteDetails [ ] | undefined
24+ ) : Set < string > {
25+ const knownSiteIds = new Set < string > ( ) ;
26+
27+ activeSites ?. forEach ( site => {
28+ if ( site . websiteRecordId ) {
29+ knownSiteIds . add ( site . websiteRecordId . toLowerCase ( ) ) ;
30+ }
31+ } ) ;
32+
33+ inactiveSites ?. forEach ( site => {
34+ if ( site . websiteRecordId ) {
35+ knownSiteIds . add ( site . websiteRecordId . toLowerCase ( ) ) ;
36+ }
37+ } ) ;
38+
39+ return knownSiteIds ;
40+ }
41+
42+ /**
43+ * Finds Power Pages sites in the parent folder that aren't in the known sites list
44+ * @param knownSiteIds Set of site IDs that should be excluded from results
45+ * @returns Array of site information objects for sites found in the parent folder
46+ */
47+ export function findOtherSites ( knownSiteIds : Set < string > , fsModule = fs , yamlModule = yaml ) : IOtherSiteInfo [ ] {
48+ traceInfo ( Constants . EventNames . ACTIONS_HUB_FIND_OTHER_SITES_CALLED , { methodName : findOtherSites . name } ) ;
49+
50+ // Get the workspace folders
51+ const workspaceFolders = vscode . workspace . workspaceFolders ;
52+ if ( ! workspaceFolders || workspaceFolders . length === 0 ) {
53+ return [ ] ;
54+ }
55+
56+ const currentWorkspaceFolder = workspaceFolders [ 0 ] . uri . fsPath ;
57+ const parentFolder = path . dirname ( currentWorkspaceFolder ) ;
58+
59+ try {
60+ // Get directories in the parent folder
61+ const items = fsModule . readdirSync ( parentFolder , { withFileTypes : true } ) ;
62+ const directories = items
63+ . filter ( item => item . isDirectory ( ) )
64+ . map ( item => path . join ( parentFolder , item . name ) ) ;
65+
66+ // Make sure we include the current workspace folder
67+ if ( ! directories . includes ( currentWorkspaceFolder ) ) {
68+ directories . push ( currentWorkspaceFolder ) ;
69+ }
70+
71+ // Check each directory for website.yml or .powerpages-site folder
72+ const otherSites : IOtherSiteInfo [ ] = [ ] ;
73+ for ( const dir of directories ) {
74+ let websiteYamlPath = getWebsiteYamlPath ( dir ) ;
75+ let hasWebsiteYamlFile = hasWebsiteYaml ( dir ) ;
76+ const powerPagesSiteFolderExists = fs . existsSync ( dir )
77+ let workingDir = dir ;
78+
79+ if ( powerPagesSiteFolderExists ) {
80+ workingDir = path . join ( dir , POWERPAGES_SITE_FOLDER ) ;
81+ websiteYamlPath = getWebsiteYamlPath ( workingDir ) ;
82+ hasWebsiteYamlFile = hasWebsiteYaml ( workingDir ) ;
83+ }
84+
85+ if ( hasWebsiteYamlFile ) {
86+ try {
87+ // Use the utility function to get website record ID
88+ const websiteId = getWebsiteRecordId ( workingDir ) ;
89+
90+ // Only include sites that aren't already in active or inactive sites
91+ if ( websiteId && ! knownSiteIds . has ( websiteId . toLowerCase ( ) ) ) {
92+ // Parse website.yml to get site details for the name
93+ const yamlContent = fsModule . readFileSync ( websiteYamlPath , UTF8_ENCODING ) ;
94+ const websiteData = yamlModule . parse ( yamlContent ) as WebsiteYaml ;
95+
96+ otherSites . push ( {
97+ name : websiteData ?. adx_name || websiteData ?. name || path . basename ( dir ) , // Use folder name as fallback
98+ websiteId : websiteId ,
99+ folderPath : dir ,
100+ isCodeSite : powerPagesSiteFolderExists
101+ } ) ;
102+ }
103+ } catch ( error ) {
104+ traceError (
105+ Constants . EventNames . ACTIONS_HUB_FIND_OTHER_SITES_YAML_PARSE_FAILED ,
106+ error as Error ,
107+ { methodName : findOtherSites . name }
108+ ) ;
109+ }
110+ }
111+ }
112+
113+ return otherSites ;
114+ } catch ( error ) {
115+ traceError (
116+ Constants . EventNames . ACTIONS_HUB_FIND_OTHER_SITES_FAILED ,
117+ error as Error ,
118+ { methodName : findOtherSites . name }
119+ ) ;
120+ return [ ] ;
121+ }
122+ }
9123
10124export const getDefaultCodeQLDatabasePath = ( ) : string => {
11125 // Use a temporary directory for the CodeQL database
@@ -14,3 +128,75 @@ export const getDefaultCodeQLDatabasePath = (): string => {
14128 return path . join ( tempDir , dbName ) ;
15129} ;
16130
131+ const sortByCreatedOn = < T extends { createdOn ?: string | null } > ( item1 : T , item2 : T ) : number => {
132+ const date1 = new Date ( item1 . createdOn || '' ) . valueOf ( ) ; //NaN if createdOn is null or undefined
133+ const date2 = new Date ( item2 . createdOn || '' ) . valueOf ( ) ;
134+ return date2 - date1 ; // Sort in descending order (newest first)
135+ }
136+
137+ export const fetchWebsites = async ( ) : Promise < { activeSites : IWebsiteDetails [ ] , inactiveSites : IWebsiteDetails [ ] , otherSites : IOtherSiteInfo [ ] } > => {
138+ traceInfo ( Constants . EventNames . ACTIONS_HUB_FETCH_WEBSITES_CALLED , { methodName : fetchWebsites . name } ) ;
139+ try {
140+ const orgInfo = PacContext . OrgInfo ;
141+ if ( ArtemisContext . ServiceResponse ?. stamp && orgInfo ) {
142+ let allSites : IWebsiteDetails [ ] = [ ] ;
143+ let activeWebsiteDetails : IWebsiteDetails [ ] = [ ] ;
144+ [ activeWebsiteDetails , allSites ] = await Promise . all ( [
145+ getActiveWebsites ( ArtemisContext . ServiceResponse ?. stamp , orgInfo . EnvironmentId ) ,
146+ getAllWebsites ( orgInfo )
147+ ] ) ;
148+ const activeSiteIds = new Set ( activeWebsiteDetails . map ( activeSite => activeSite . websiteRecordId ) ) ;
149+ const inactiveWebsiteDetails = allSites ?. filter ( site => ! activeSiteIds . has ( site . websiteRecordId ) ) || [ ] ;
150+ activeWebsiteDetails = activeWebsiteDetails . map ( detail => {
151+ const site = allSites . find ( site => site . websiteRecordId === detail . websiteRecordId ) ;
152+
153+ if ( ! site ) {
154+ return detail ;
155+ }
156+
157+ return {
158+ ...detail ,
159+ siteManagementUrl : site . siteManagementUrl ,
160+ isCodeSite : site . isCodeSite ,
161+ createdOn : site . createdOn ,
162+ creator : site . creator ,
163+ }
164+ } ) ;
165+
166+ activeWebsiteDetails . sort ( sortByCreatedOn ) ;
167+ inactiveWebsiteDetails . sort ( sortByCreatedOn ) ;
168+
169+ const currentEnvSiteIds = createKnownSiteIdsSet ( activeWebsiteDetails , inactiveWebsiteDetails ) ;
170+ const otherSites = findOtherSites ( currentEnvSiteIds ) ;
171+
172+ return { activeSites : activeWebsiteDetails , inactiveSites : inactiveWebsiteDetails , otherSites : otherSites } ;
173+ }
174+ } catch ( error ) {
175+ traceError ( Constants . EventNames . ACTIONS_HUB_FETCH_WEBSITES_FAILED , error as Error , { methodName : fetchWebsites . name } ) ;
176+ }
177+
178+ return { activeSites : [ ] , inactiveSites : [ ] , otherSites : [ ] } ;
179+ }
180+
181+ export const getStudioBaseUrl = ( ) : string => {
182+ const artemisContext = ArtemisContext . ServiceResponse ;
183+
184+ switch ( artemisContext . stamp ) {
185+ case ServiceEndpointCategory . TEST :
186+ return Constants . StudioEndpoints . TEST ;
187+ case ServiceEndpointCategory . PREPROD :
188+ return Constants . StudioEndpoints . TEST ; //Studio for preprod is same as test
189+ case ServiceEndpointCategory . PROD :
190+ return Constants . StudioEndpoints . PROD ;
191+ case ServiceEndpointCategory . DOD :
192+ return Constants . StudioEndpoints . DOD ;
193+ case ServiceEndpointCategory . GCC :
194+ return Constants . StudioEndpoints . GCC ;
195+ case ServiceEndpointCategory . HIGH :
196+ return Constants . StudioEndpoints . HIGH ;
197+ case ServiceEndpointCategory . MOONCAKE :
198+ return Constants . StudioEndpoints . MOONCAKE ;
199+ }
200+
201+ return "" ;
202+ }
0 commit comments