this repo has no description
at main 28 kB view raw
1import * as validation from "@jet/environment/json/validation"; 2import * as models from "../../api/models"; 3import * as serverData from "../../foundation/json-parsing/server-data"; 4import * as mediaAttributes from "../../foundation/media/attributes"; 5import * as mediaDataStructure from "../../foundation/media/data-structure"; 6import * as mediaRelationship from "../../foundation/media/relationships"; 7import { Path, Protocol } from "../../foundation/network/url-constants"; 8import * as client from "../../foundation/wrappers/client"; 9import { watchosDeveloperRelationshipKey } from "./developer-request"; 10import * as content from "../content/content"; 11import * as lockups from "../lockups/lockups"; 12import * as metricsHelpersClicks from "../metrics/helpers/clicks"; 13import * as metricsHelpersImpressions from "../metrics/helpers/impressions"; 14import * as metricsHelpersLocation from "../metrics/helpers/location"; 15import * as metricsHelpersPage from "../metrics/helpers/page"; 16import * as room from "../room/room-common"; 17export class DeveloperRoomToken extends room.RoomPageToken { 18} 19/// Ordering of shelves for macOS developer page per Relationship key. 20/// @seealso mediaUrlMapping.macOSDeveloperRelationshipKeys 21const macosDeveloperRelationshipOrder = [ 22 "latest-release-app", 23 "arcade-apps", 24 "app-bundles", 25 "mac-apps", 26 "mac-os-compatible-ios-apps", 27]; 28/// Ordering of shelves for iOS developer page per Relationship key. 29/// @seealso mediaUrlMapping.iosDeveloperRelationshipKeys 30const iosDeveloperRelationshipOrder = [ 31 "latest-release-app", 32 "arcade-apps", 33 "system-apps", 34 "app-bundles", 35 "ios-apps", 36 "imessage-apps", 37 "watch-apps", 38 "atv-apps", 39]; 40/// The threshold for when to show the see all button. 41const seeAllThreshold = 8; 42/// Ordering of shelves for macOS developer page per Relationship key. 43/// @seealso mediaUrlMapping.macOSDeveloperRelationshipKeys 44const visionOSDeveloperRelationshipOrder = [ 45 "latest-release-app", 46 "xros-apps", 47 "arcade-apps", 48 "ios-apps", 49]; 50/// Ordering of shelves for the web developer page per Relationship key. 51/// @seealso mediaUrlMapping.macOSDeveloperRelationshipKeys 52const webDeveloperRelationshipOrder = [ 53 "latest-release-app", 54 "system-apps", 55 "app-bundles", 56 "ios-apps", 57 "mac-apps", 58 "arcade-apps", 59 "xros-apps", 60 "atv-apps", 61 "watch-apps", 62 "imessage-apps", 63]; 64export class DeveloperPageShelfToken { 65} 66export function developerPageFromResponse(objectGraph, response) { 67 return validation.context("developerPageFromResponse", () => { 68 const developerData = response.data.length ? response.data[0] : null; 69 if (!developerData) { 70 return null; 71 } 72 const metricsPageInformation = metricsHelpersPage.metricsPageInformationFromMediaApiResponse(objectGraph, "Artist", developerData.id, response); 73 const locationTracker = metricsHelpersLocation.newLocationTracker(); 74 const shelves = shelvesForDeveloperData(objectGraph, developerData, metricsPageInformation, locationTracker); 75 // A single shelf should be vertical 76 if (shelves.length === 1) { 77 shelves[0].isHorizontal = false; 78 } 79 // Add developer description 80 const itunesNotes = content.notesFromData(objectGraph, developerData, "standard"); 81 if (itunesNotes) { 82 const paragraph = new models.Paragraph(itunesNotes, "text/x-apple-as3-nqml"); 83 const shelf = new models.Shelf("paragraph"); 84 shelf.items = [paragraph]; 85 shelves.unshift(shelf); 86 } 87 // Create the page 88 const page = new models.GenericPage(shelves); 89 page.title = mediaAttributes.attributeAsString(developerData, "name"); 90 if (objectGraph.client.deviceType !== "watch") { 91 page.presentationOptions = ["prefersLargeTitle"]; 92 } 93 page.canonicalURL = mediaAttributes.attributeAsString(developerData, "url"); 94 // Setup metrics 95 metricsHelpersPage.addMetricsEventsToPageWithInformation(objectGraph, page, metricsPageInformation); 96 // Add the uber 97 const uber = mediaAttributes.attributeAsDictionary(developerData, "editorialArtwork.bannerUber"); 98 if (uber && !objectGraph.client.isVision) { 99 const uberArtwork = content.artworkFromApiArtwork(objectGraph, uber, { 100 cropCode: "sr", 101 useCase: 21 /* content.ArtworkUseCase.Uber */, 102 }); 103 page.uber = uberArtwork; 104 if (objectGraph.client.isiOS || objectGraph.client.isWeb) { 105 const uberShelf = new models.Shelf("uber"); 106 const uberModel = new models.Uber("above"); 107 uberModel.artwork = uberArtwork; 108 uberShelf.items = [uberModel]; 109 uberModel.title = page.title; 110 shelves.unshift(uberShelf); 111 page.presentationOptions.push("prefersNonStandardBackButton"); 112 if (!objectGraph.client.isWeb) { 113 page.presentationOptions.push("prefersOverlayedPageHeader"); 114 } 115 } 116 } 117 return page; 118 }); 119} 120function shelvesForDeveloperData(objectGraph, data, metricsPageInformation, locationTracker) { 121 switch (objectGraph.client.deviceType) { 122 case "mac": 123 return macosShelvesForDeveloperData(objectGraph, data, metricsPageInformation, locationTracker); 124 case "watch": 125 return flatShelvesForDeveloperData(objectGraph, "smallLockup", data, watchosDeveloperRelationshipKey, objectGraph.loc.string("DEVELOPER_WATCH"), metricsPageInformation, locationTracker); 126 case "vision": 127 return orderedShelvesForDeveloperData(objectGraph, data, visionOSDeveloperRelationshipOrder, metricsPageInformation, locationTracker); 128 case "web": 129 return orderedShelvesForDeveloperData(objectGraph, data, webDeveloperRelationshipOrder, metricsPageInformation, locationTracker); 130 default: 131 return orderedShelvesForDeveloperData(objectGraph, data, iosDeveloperRelationshipOrder, metricsPageInformation, locationTracker); 132 } 133} 134/** 135 * Returns the iOS shelf title for a given relationship. 136 * @param relationshipKey The relationship key. 137 * @param developerData Media API data for the developer page. 138 * @returns The localized shelf title. 139 */ 140function iosShelfTitle(objectGraph, relationshipKey, developerData) { 141 switch (relationshipKey) { 142 case "latest-release-app": 143 return objectGraph.loc.string("DEVELOPER_LATEST_RELEASE"); 144 case "system-apps": 145 return objectGraph.loc.string("DEVELOPER_SYSTEM_APPS"); 146 case "imessage-apps": 147 return objectGraph.loc.string("DEVELOPER_IMESSAGE"); 148 case "watch-apps": 149 return objectGraph.loc.string("DEVELOPER_WATCH"); 150 case "atv-apps": 151 return objectGraph.loc.string("DEVELOPER_TV"); 152 case "app-bundles": 153 return objectGraph.loc.string("DEVELOPER_BUNDLES"); 154 case "xros-apps": 155 return objectGraph.loc.string("DEVELOPER_VISION"); 156 case "ios-apps": 157 const hasApps = mediaAttributes.attributeAsBooleanOrFalse(developerData, "hasApps"); 158 const hasGames = mediaAttributes.attributeAsBooleanOrFalse(developerData, "hasGames"); 159 if (hasApps && hasGames) { 160 return objectGraph.loc.string("DEVELOPER_APPS_AND_GAMES"); 161 } 162 else if (hasGames) { 163 return objectGraph.loc.string("DEVELOPER_GAMES"); 164 } 165 else { 166 return objectGraph.loc.string("DEVELOPER_APPS"); 167 } 168 case "arcade-apps": 169 return objectGraph.loc.string("DEVELOPER_APPLE_ARCADE"); 170 default: 171 return null; 172 } 173} 174/** 175 * Returns the web shelf title for a given relationship. 176 * @param relationshipKey The relationship key. 177 * @param developerData Media API data for the developer page. 178 * @returns The localized shelf title. 179 */ 180function webShelfTitle(objectGraph, relationshipKey, developerData) { 181 switch (relationshipKey) { 182 case "latest-release-app": 183 return objectGraph.loc.string("DEVELOPER_LATEST_RELEASE"); 184 case "system-apps": 185 return objectGraph.loc.string("DEVELOPER_SYSTEM_APPS"); 186 case "imessage-apps": 187 return objectGraph.loc.string("DEVELOPER_IMESSAGE"); 188 case "watch-apps": 189 return objectGraph.loc.string("DEVELOPER_WATCH"); 190 case "atv-apps": 191 return objectGraph.loc.string("DEVELOPER_TV"); 192 case "app-bundles": 193 return objectGraph.loc.string("DEVELOPER_BUNDLES"); 194 case "xros-apps": 195 return objectGraph.loc.string("DEVELOPER_VISION"); 196 case "ios-apps": 197 return objectGraph.loc.string("DEVELOPER_PHONE_PAD_APPS"); 198 case "arcade-apps": 199 return objectGraph.loc.string("DEVELOPER_APPLE_ARCADE"); 200 case "mac-apps": 201 return objectGraph.loc.string("DEVELOPER_MAC_APPS"); 202 case "mac-os-compatible-ios-apps": 203 return objectGraph.loc.string("DEVELOPER_PHONE_PAD_APPS"); 204 default: 205 return null; 206 } 207} 208function orderedShelvesForDeveloperData(objectGraph, developerData, developerRelationshipOrdering, metricsPageInformation, locationTracker) { 209 var _a, _b; 210 if (objectGraph.host.isiOS) { 211 // Filter duplicate Arcade apps on iOS 212 filterDuplicateApps(developerData, "arcade-apps", ["ios-apps", "atv-apps"]); 213 } 214 let shelfContentType; 215 let artworkUseCase; 216 switch (objectGraph.client.deviceType) { 217 case "tv": 218 shelfContentType = "mediumLockup"; 219 artworkUseCase = 2 /* content.ArtworkUseCase.LockupIconMedium */; 220 break; 221 case "web": 222 shelfContentType = "mediumLockup"; 223 artworkUseCase = 2 /* content.ArtworkUseCase.LockupIconMedium */; 224 break; 225 default: 226 shelfContentType = "smallLockup"; 227 artworkUseCase = 1 /* content.ArtworkUseCase.LockupIconSmall */; 228 break; 229 } 230 let shelfCount = 0; 231 const shelves = []; 232 for (const relationship of developerRelationshipOrdering) { 233 const dataContainer = mediaRelationship.relationship(developerData, relationship); 234 const sectionData = serverData.asArrayOrEmpty(dataContainer, "data"); 235 const contentCount = sectionData.length; 236 if (contentCount === 0) { 237 continue; 238 } 239 // Skip the latest release shelf if there are no items 240 // Note: This typically happens on the Apple developer page 241 // if the latest release is a system app that you're not eligible for 242 if (relationship === "latest-release-app" && contentCount === 0) { 243 continue; 244 } 245 // Setup some content specific options 246 let clientIdentifier; 247 if (relationship === "imessage-apps") { 248 clientIdentifier = client.messagesIdentifier; 249 } 250 else if (relationship === "watch-apps") { 251 clientIdentifier = client.watchIdentifier; 252 } 253 else if (relationship === "atv-apps") { 254 clientIdentifier = client.tvIdentifier; 255 } 256 else { 257 clientIdentifier = client.appStoreIdentifier; 258 } 259 // Determine the title 260 let shelfTitle; 261 if (objectGraph.client.isWeb) { 262 shelfTitle = webShelfTitle(objectGraph, relationship, developerData); 263 } 264 else { 265 shelfTitle = iosShelfTitle(objectGraph, relationship, developerData); 266 } 267 // Create a metrics context 268 metricsHelpersLocation.pushContentLocation(objectGraph, { 269 pageInformation: metricsPageInformation, 270 locationTracker: locationTracker, 271 idType: "sequential", 272 id: `${shelfCount}`, 273 targetType: "swoosh", 274 }, shelfTitle); 275 // Create the shelf 276 const listOptions = { 277 lockupOptions: { 278 metricsOptions: { 279 pageInformation: metricsPageInformation, 280 locationTracker: locationTracker, 281 }, 282 clientIdentifierOverride: clientIdentifier, 283 artworkUseCase: artworkUseCase, 284 }, 285 filter: 76532 /* filtering.Filter.DeveloperPage */, 286 }; 287 // Determine the ids we need to load 288 const remainingData = sectionData.filter((data) => { 289 return serverData.isNullOrEmpty(data.attributes); 290 }); 291 // Vision doesn't support See All on developer page shelves currently. 292 const shouldShowSeeAll = (((_a = dataContainer.next) === null || _a === void 0 ? void 0 : _a.length) > 0 || contentCount >= seeAllThreshold) && 293 !(objectGraph.client.isVision || objectGraph.client.isWeb); 294 const shelf = shelfForData(objectGraph, shelfTitle, developerData.id, sectionData, relationship, shelfContentType, listOptions, metricsPageInformation, locationTracker, dataContainer.href, shouldShowSeeAll); 295 // Ensure we're not too high 296 const itemCount = shelf.items.length + remainingData.length; 297 if (objectGraph.client.isVision) { 298 if (itemCount < 5) { 299 shelf.rowsPerColumn = 1; 300 } 301 else if (itemCount < 10) { 302 shelf.rowsPerColumn = 2; 303 } 304 else { 305 shelf.rowsPerColumn = 3; 306 } 307 } 308 else if (objectGraph.client.isWeb) { 309 shelf.rowsPerColumn = itemCount > 3 ? 2 : 1; 310 } 311 else if (itemCount < 3) { 312 shelf.rowsPerColumn = itemCount; 313 } 314 // Add metrics before serializing token for url 315 const shelfMetricsOptions = { 316 id: null, 317 kind: null, 318 softwareType: null, 319 targetType: "swoosh", 320 title: shelf.title, 321 pageInformation: metricsPageInformation, 322 locationTracker: locationTracker, 323 idType: null, 324 }; 325 metricsHelpersLocation.popLocation(locationTracker); 326 metricsHelpersImpressions.addImpressionFields(objectGraph, shelf, shelfMetricsOptions); 327 metricsHelpersLocation.nextPosition(locationTracker); 328 if (remainingData.length) { 329 const token = new DeveloperPageShelfToken(); 330 token.title = shelfTitle; 331 token.developerId = developerData.id; 332 token.contentType = shelfContentType; 333 token.remainingData = remainingData; 334 token.lockupListOptions = listOptions; 335 token.relationship = relationship; 336 token.roomUrl = dataContainer.href; 337 token.shouldShowSeeAll = shouldShowSeeAll; 338 token.hasExistingContent = serverData.isDefinedNonNullNonEmpty(shelf.items); 339 shelf.url = 340 `${Protocol.internal}:/${Path.developer}/${Path.shelf}/` + encodeURIComponent(JSON.stringify(token)); 341 } 342 // Don't add the shelf if there are no items in it, and there is no more content to fetch. 343 if (shelf.items.length > 0 || ((_b = shelf.url) === null || _b === void 0 ? void 0 : _b.length) > 0) { 344 shelves.push(shelf); 345 shelfCount++; 346 } 347 } 348 return shelves; 349} 350/** 351 * Returns the macOS shelf title for a given relationship. 352 * @param relationshipKey The relationship key. 353 * @param developerData Media API data for the developer page. 354 * @returns The localized shelf title. 355 */ 356function macosShelfTitle(objectGraph, relationshipKey, developerData) { 357 switch (relationshipKey) { 358 case "latest-release-app": 359 return objectGraph.loc.string("DEVELOPER_LATEST_RELEASE"); 360 case "app-bundles": 361 return objectGraph.loc.string("DEVELOPER_BUNDLES"); 362 case "mac-apps": 363 if (objectGraph.appleSilicon.isSupportEnabled) { 364 return objectGraph.loc.string("DEVELOPER_MAC_APPS"); 365 } 366 else { 367 const hasApps = mediaAttributes.attributeAsBooleanOrFalse(developerData, "hasApps"); 368 const hasGames = mediaAttributes.attributeAsBooleanOrFalse(developerData, "hasGames"); 369 if (hasApps && hasGames) { 370 return objectGraph.loc.string("DEVELOPER_APPS_AND_GAMES"); 371 } 372 else if (hasGames) { 373 return objectGraph.loc.string("DEVELOPER_GAMES"); 374 } 375 else { 376 return objectGraph.loc.string("DEVELOPER_APPS"); 377 } 378 } 379 case "mac-os-compatible-ios-apps": 380 return objectGraph.loc.string("DEVELOPER_PHONE_PAD_APPS"); 381 case "arcade-apps": 382 return objectGraph.loc.string("DEVELOPER_APPLE_ARCADE"); 383 default: 384 return null; 385 } 386} 387function macosShelvesForDeveloperData(objectGraph, developerData, metricsPageInformation, locationTracker) { 388 var _a; 389 // Filter duplicate apps 390 if (objectGraph.appleSilicon.isSupportEnabled) { 391 filterDuplicateApps(developerData, "arcade-apps", ["mac-apps", "mac-os-compatible-ios-apps"]); 392 filterDuplicateApps(developerData, "mac-apps", ["mac-os-compatible-ios-apps"]); 393 } 394 else { 395 filterDuplicateApps(developerData, "arcade-apps", ["mac-apps"]); 396 } 397 const shelfContentType = "smallLockup"; 398 const artworkUseCase = 1 /* content.ArtworkUseCase.LockupIconSmall */; 399 let shelfCount = 0; 400 const shelves = []; 401 for (const relationship of macosDeveloperRelationshipOrder) { 402 const dataContainer = mediaRelationship.relationship(developerData, relationship); 403 const sectionData = serverData.asArrayOrEmpty(dataContainer, "data"); 404 const contentCount = sectionData.length; 405 if (contentCount === 0) { 406 continue; 407 } 408 // Skip the latest release shelf if there are no items 409 // Note: This typically happens on the Apple developer page 410 // if the latest release is a system app that you're not eligible for 411 if (relationship === "latest-release-app" && contentCount === 0) { 412 continue; 413 } 414 // Determine the title 415 const shelfTitle = macosShelfTitle(objectGraph, relationship, developerData); 416 // Create a metrics context 417 metricsHelpersLocation.pushContentLocation(objectGraph, { 418 pageInformation: metricsPageInformation, 419 locationTracker: locationTracker, 420 idType: "sequential", 421 id: `${shelfCount}`, 422 targetType: "swoosh", 423 }, shelfTitle); 424 // Create the shelf 425 const listOptions = { 426 lockupOptions: { 427 metricsOptions: { 428 pageInformation: metricsPageInformation, 429 locationTracker: locationTracker, 430 }, 431 artworkUseCase: artworkUseCase, 432 }, 433 filter: 76532 /* filtering.Filter.DeveloperPage */, 434 }; 435 // Determine the ids we need to load 436 const remainingData = sectionData.filter((data) => { 437 return serverData.isNullOrEmpty(data.attributes); 438 }); 439 const shouldShowSeeAll = ((_a = dataContainer.next) === null || _a === void 0 ? void 0 : _a.length) > 0 || contentCount >= seeAllThreshold; 440 const shelf = shelfForData(objectGraph, shelfTitle, developerData.id, sectionData, relationship, shelfContentType, listOptions, metricsPageInformation, locationTracker, dataContainer.href, shouldShowSeeAll); 441 // Ensure we're not too high 442 const itemCount = shelf.items.length + remainingData.length; 443 if (itemCount < 3) { 444 shelf.rowsPerColumn = itemCount; 445 } 446 // Add metrics before serializing token for url 447 const shelfMetricsOptions = { 448 id: null, 449 kind: null, 450 softwareType: null, 451 targetType: "swoosh", 452 title: shelf.title, 453 pageInformation: metricsPageInformation, 454 locationTracker: locationTracker, 455 idType: null, 456 }; 457 metricsHelpersLocation.popLocation(locationTracker); 458 metricsHelpersImpressions.addImpressionFields(objectGraph, shelf, shelfMetricsOptions); 459 metricsHelpersLocation.nextPosition(locationTracker); 460 if (remainingData.length) { 461 const token = new DeveloperPageShelfToken(); 462 token.title = shelfTitle; 463 token.developerId = developerData.id; 464 token.contentType = "smallLockup"; 465 token.remainingData = remainingData; 466 token.lockupListOptions = listOptions; 467 token.relationship = relationship; 468 token.roomUrl = dataContainer.href; 469 token.shouldShowSeeAll = shouldShowSeeAll; 470 token.hasExistingContent = serverData.isDefinedNonNullNonEmpty(shelf.items); 471 shelf.url = 472 `${Protocol.internal}:/${Path.developer}/${Path.shelf}/` + encodeURIComponent(JSON.stringify(token)); 473 } 474 // Don't add the shelf if there are no items in it 475 if (shelf.items.length > 0) { 476 shelves.push(shelf); 477 shelfCount++; 478 } 479 } 480 return shelves; 481} 482/** 483 * Creates a list of apps for the given relationship type. 484 */ 485function flatShelvesForDeveloperData(objectGraph, contentType, developerData, relationshipType, shelfTitle, metricsPageInformation, locationTracker) { 486 const dataCollection = mediaRelationship.relationshipCollection(developerData, relationshipType); 487 const listOptions = { 488 lockupOptions: { 489 metricsOptions: { 490 pageInformation: metricsPageInformation, 491 locationTracker: locationTracker, 492 }, 493 artworkUseCase: 1 /* content.ArtworkUseCase.LockupIconSmall */, 494 }, 495 filter: 76532 /* filtering.Filter.DeveloperPage */, 496 }; 497 // Create a metrics context 498 metricsHelpersLocation.pushContentLocation(objectGraph, { 499 pageInformation: metricsPageInformation, 500 locationTracker: locationTracker, 501 idType: "sequential", 502 id: `0`, 503 targetType: "swoosh", 504 }, shelfTitle); 505 const shelf = shelfForData(objectGraph, shelfTitle, developerData.id, dataCollection, relationshipType, contentType, listOptions, metricsPageInformation, locationTracker, null, false); 506 // Determine the ids we need to load 507 const remainingData = dataCollection.filter((data) => { 508 return serverData.isNullOrEmpty(data.attributes); 509 }); 510 // Add metrics before serializing token for url 511 const shelfMetricsOptions = { 512 id: null, 513 kind: null, 514 softwareType: null, 515 targetType: "swoosh", 516 title: shelfTitle, 517 pageInformation: metricsPageInformation, 518 locationTracker: locationTracker, 519 idType: null, 520 }; 521 metricsHelpersLocation.popLocation(locationTracker); 522 metricsHelpersImpressions.addImpressionFields(objectGraph, shelf, shelfMetricsOptions); 523 metricsHelpersLocation.nextPosition(locationTracker); 524 if (remainingData.length) { 525 const token = new DeveloperPageShelfToken(); 526 token.title = shelfTitle; 527 token.developerId = developerData.id; 528 token.contentType = contentType; 529 token.remainingData = remainingData; 530 token.lockupListOptions = listOptions; 531 token.hasExistingContent = serverData.isDefinedNonNullNonEmpty(shelf.items); 532 shelf.url = 533 `${Protocol.internal}:/${Path.developer}/${Path.shelf}/` + encodeURIComponent(JSON.stringify(token)); 534 } 535 return [shelf]; 536} 537export function shelfForData(objectGraph, title, developerId, dataArray, developerRelationship, contentType, listOptions, pageInformation, locationTracker, roomUrl, includeSeeAll) { 538 const shelf = new models.Shelf(contentType); 539 shelf.title = title; 540 switch (contentType) { 541 case "screenshotsLockup": 542 shelf.items = lockups.screenshotsLockupsFromData(objectGraph, dataArray, listOptions); 543 shelf.isHorizontal = false; 544 shelf.presentationHints = { showSupplementaryText: false }; 545 break; 546 case "smallLockup": 547 default: 548 shelf.items = lockups.lockupsFromData(objectGraph, dataArray, listOptions); 549 shelf.isHorizontal = objectGraph.client.deviceType !== "watch"; 550 break; 551 } 552 if (includeSeeAll) { 553 // Create token for the see all room 554 const roomToken = new DeveloperRoomToken(); 555 roomToken.title = title; 556 roomToken.url = roomUrl; 557 roomToken.developerId = developerId; 558 roomToken.relationshipId = developerRelationship; 559 roomToken.clientIdentifierOverride = listOptions.lockupOptions.clientIdentifierOverride; 560 const seeAllAction = new models.FlowAction("page"); 561 seeAllAction.pageUrl = developerRoomUrlWithToken(objectGraph, roomToken); 562 seeAllAction.title = objectGraph.loc.string("ACTION_SEE_ALL"); 563 seeAllAction.pageData = room.seeAllPage(objectGraph, title); 564 metricsHelpersClicks.addClickEventToSeeAllAction(objectGraph, seeAllAction, seeAllAction.pageUrl, { 565 pageInformation, 566 locationTracker, 567 }); 568 shelf.seeAllAction = seeAllAction; 569 } 570 return shelf; 571} 572/** 573 * Determines the URL to use for the developer room page. 574 * @param {string} token The token to use. 575 * @returns {string} The string to use for the developer room page. 576 */ 577function developerRoomUrlWithToken(objectGraph, token) { 578 if (!serverData.isDefinedNonNull(token)) { 579 return null; 580 } 581 return `${Protocol.internal}:/${Path.developer}/${Path.room}/` + encodeURIComponent(JSON.stringify(token)); 582} 583/** 584 * Prune duplicate entries for apps that can appear in other shelves by modifying `developerData` in place. 585 * For example if `arcade-apps` relation contains id `12345`, we want to prune `12345` from shelves like "Games" and "Apple TV" 586 */ 587function filterDuplicateApps(developerData, authoritativeRelationshipKey, filteredRelationshipKeys) { 588 const arcadeRelationship = mediaRelationship.relationship(developerData, authoritativeRelationshipKey); 589 if (serverData.isNull(arcadeRelationship)) { 590 return; // No arcade relationship 591 } 592 const arcadeApps = mediaDataStructure.dataCollectionFromDataContainer(arcadeRelationship); 593 if (serverData.isNull(arcadeApps)) { 594 return; // No arcade relationship data 595 } 596 // IDs to filter from other shelves since they are in arcade shelf 597 const arcadeAppIds = arcadeApps.map((app) => app.id); 598 for (const relationshipKeyToFilter of filteredRelationshipKeys) { 599 const relationshipToFilter = mediaRelationship.relationship(developerData, relationshipKeyToFilter); 600 if (serverData.isNull(relationshipToFilter)) { 601 continue; // Skip if relationship didn't exist 602 } 603 const relationshipDataToFilter = mediaDataStructure.dataCollectionFromDataContainer(relationshipToFilter); 604 if (serverData.isNull(relationshipToFilter)) { 605 continue; // Skip if relationship had no `data` 606 } 607 // Overwrite with filtered data 608 developerData.relationships[relationshipKeyToFilter].data = relationshipDataToFilter.filter((data) => !arcadeAppIds.includes(data.id)); 609 } 610} 611//# sourceMappingURL=developer-common.js.map