0"
class="fx-empty list-button-group">
diff --git a/src/app/components/results-menu/baseline-results-menu/baseline-results-menu.component.ts b/src/app/components/results-menu/baseline-results-menu/baseline-results-menu.component.ts
index 0b293d402..2239933a0 100644
--- a/src/app/components/results-menu/baseline-results-menu/baseline-results-menu.component.ts
+++ b/src/app/components/results-menu/baseline-results-menu/baseline-results-menu.component.ts
@@ -10,7 +10,7 @@ import * as queueStore from '@store/queue';
import {
ScreenSizeService, MapService, ScenesService, PairService,
- Hyp3Service
+ Hyp3Service, PossibleHyp3JobsService,
} from '@services';
import { SubSink } from 'subsink';
@@ -64,6 +64,7 @@ export class BaselineResultsMenuComponent implements OnInit, OnDestroy {
private scenesService: ScenesService,
private pairService: PairService,
private hyp3: Hyp3Service,
+ private possibleHyp3JobsService: PossibleHyp3JobsService,
) { }
ngOnInit(): void {
@@ -76,20 +77,19 @@ export class BaselineResultsMenuComponent implements OnInit, OnDestroy {
this.products = products;
this.downloadableProds = this.hyp3.downloadable(products);
this.pairs = [ ...pairs, ...custom ];
-
- this.hyp3able = this.hyp3.getHyp3ableProducts([
- ...this.products.map(prod => [prod]),
- ...this.pairs?.sort((a, b) => {
- if (a.metadata.date < b.metadata.date) {
- return -1;
- }
- return 1;
- })
- ]);
}
)
);
+ this.subs.add(
+ this.possibleHyp3JobsService.possibleJobs$
+ .subscribe(
+ possibleJobs => {
+ this.hyp3able = this.hyp3.getHyp3ableProducts(possibleJobs);
+ }
+ )
+ );
+
this.subs.add(
this.screenSize.breakpoint$.subscribe(
point => this.breakpoint = point
diff --git a/src/app/components/results-menu/results-menu.component.html b/src/app/components/results-menu/results-menu.component.html
index 59e3d4813..78289611f 100644
--- a/src/app/components/results-menu/results-menu.component.html
+++ b/src/app/components/results-menu/results-menu.component.html
@@ -19,7 +19,6 @@
diff --git a/src/app/components/results-menu/scene-detail/scene-detail.component.html b/src/app/components/results-menu/scene-detail/scene-detail.component.html
index 5e074af16..46d44cbf4 100644
--- a/src/app/components/results-menu/scene-detail/scene-detail.component.html
+++ b/src/app/components/results-menu/scene-detail/scene-detail.component.html
@@ -274,12 +274,13 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/app/components/shared/on-demand-add-menu/on-demand-add-menu.component.ts b/src/app/components/shared/on-demand-add-menu/on-demand-add-menu.component.ts
index 752bbca9c..82ff5df2d 100644
--- a/src/app/components/shared/on-demand-add-menu/on-demand-add-menu.component.ts
+++ b/src/app/components/shared/on-demand-add-menu/on-demand-add-menu.component.ts
@@ -92,37 +92,39 @@ export class OnDemandAddMenuComponent implements OnInit {
}
const slcProducts = this.findSLCs(byProductType).products;
- return slcProducts.length >= 1 &&
- this.isNotReferenceScene(slcProducts);
+ return (
+ slcProducts.length >= 1 &&
+ this.isNotReferenceScene(slcProducts)
+ );
}
private findSLCs(byProductType: Hyp3ableByProductType[]): Hyp3ableByProductType {
- return byProductType.find(prod => prod.productType === 'SLC');
+ return byProductType.find(prod => prod.productType === 'SLC' || prod.productType === 'BURST');
}
private isNotReferenceScene(products: CMRProduct[][]): boolean {
return products[0][0].id !== this.referenceScene.id ||
- products[products.length - 1][0].id !== this.referenceScene.id;
+ products[products.length - 1][0].id !== this.referenceScene.id;
}
public queueBaselinePairOnDemand(products: models.CMRProduct[][], job_type: models.Hyp3JobType) {
products = products.filter(prod => prod[0].id !== this.referenceScene.id);
const jobs: models.QueuedHyp3Job[] = products.map(product => {
return {
- granules: [this.referenceScene, product[0]]?.sort((a, b) => {
- if (a.metadata.date < b.metadata.date) {
- return -1;
- }
- return 1;
- }),
- job_type
- } as models.QueuedHyp3Job;
- });
+ granules: [this.referenceScene, product[0]]?.sort((a, b) => {
+ if (a.metadata.date < b.metadata.date) {
+ return -1;
+ }
+ return 1;
+ }),
+ job_type
+ } as models.QueuedHyp3Job;
+ });
this.store$.dispatch(new queueStore.AddJobs(jobs));
}
- public onOpenHelp(infoUrl) {
+ public onOpenHelp(infoUrl: string) {
window.open(infoUrl);
}
}
diff --git a/src/app/components/shared/selectors/dataset-selector/dataset-selector.component.html b/src/app/components/shared/selectors/dataset-selector/dataset-selector.component.html
index fd5a790ce..0f538bbb3 100644
--- a/src/app/components/shared/selectors/dataset-selector/dataset-selector.component.html
+++ b/src/app/components/shared/selectors/dataset-selector/dataset-selector.component.html
@@ -26,7 +26,8 @@
{{ dataset.name }}
-
+
(beta)
diff --git a/src/app/components/shared/selectors/job-product-name-selector/job-product-name-selector.component.ts b/src/app/components/shared/selectors/job-product-name-selector/job-product-name-selector.component.ts
index df137f13c..9a5d0e90f 100644
--- a/src/app/components/shared/selectors/job-product-name-selector/job-product-name-selector.component.ts
+++ b/src/app/components/shared/selectors/job-product-name-selector/job-product-name-selector.component.ts
@@ -58,14 +58,26 @@ export class JobProductNameSelectorComponent implements OnInit, OnDestroy {
);
const fileNames = this.scenesService.scenes$.pipe(
- map(scenes =>
- scenes.map(scene => scene.metadata.fileName.toLowerCase().split('.')[0])
+ map(scenes => scenes
+ .map(
+ scene => {
+ const filename = scene.metadata.fileName || '';
+ return filename.toLowerCase().split('.')[0];
+ })
)
);
this.subs.add(
this.store$.select(getScenes).subscribe(
- res => this.unfilteredScenes = Array.from(new Set(res.map(scene => scene.metadata.fileName.toLowerCase().split('.')[0])))
+ res => this.unfilteredScenes = Array.from(
+ new Set(
+ res
+ .map(scene => {
+ const filename = scene.metadata.fileName || '';
+ return filename.toLowerCase().split('.')[0];
+ })
+ )
+ )
)
);
diff --git a/src/app/models/hyp3-jobs.model.ts b/src/app/models/hyp3-jobs.model.ts
index db6ef1227..d2fff318c 100644
--- a/src/app/models/hyp3-jobs.model.ts
+++ b/src/app/models/hyp3-jobs.model.ts
@@ -1,4 +1,4 @@
-import { sentinel_1 } from './dataset.model';
+import { sentinel_1, sentinel_1_bursts } from './dataset.model';
import { Hyp3JobType, JobOptionType } from './hyp3-job-type.model';
export const RtcGammaJobType: Hyp3JobType = {
@@ -230,6 +230,50 @@ export const InsarGammaJobType: Hyp3JobType = {
}]
};
+export const InsarIsceBurstJobType: Hyp3JobType = {
+ id: 'INSAR_ISCE_BURST',
+ name: 'InSAR ISCE Burst',
+ infoUrl: 'https://hyp3-docs.asf.alaska.edu/guides/burst_insar_product_guide/',
+ description: `INSAR_DESC`,
+ numProducts: 2,
+ productTypes: [{
+ dataset: sentinel_1_bursts,
+ productTypes: [
+ 'BURST',
+ ],
+ beamModes: ['IW'],
+ polarizations: [
+ 'VV', 'HH'
+ ]
+ }],
+ options: [{
+ name: 'Looks',
+ apiName: 'looks',
+ type: JobOptionType.DROPDOWN,
+ options: [{
+ name: '20x4',
+ apiValue: '20x4'
+ }, {
+ name: '10x2',
+ apiValue: '10x2'
+ }, {
+ name: '5x1',
+ apiValue: '5x1'
+ }],
+ default: '20x4',
+ info: `Number of looks to take in range and azimuth.`
+ }, {
+ name: 'Water Mask',
+ apiName: 'apply_water_mask',
+ type: JobOptionType.TOGGLE,
+ default: false,
+ info: `
+ Sets pixels over coastal and large inland waterbodies as invalid
+ for phase unwrapping.
+ `
+ }]
+};
+
export const AutoRift: Hyp3JobType = {
id: 'AUTORIFT',
name: 'autoRIFT',
@@ -252,6 +296,7 @@ export const AutoRift: Hyp3JobType = {
export const hyp3JobTypes = {
RTC_GAMMA: RtcGammaJobType,
INSAR_GAMMA: InsarGammaJobType,
+ INSAR_ISCE_BURST: InsarIsceBurstJobType,
AUTORIFT: AutoRift
};
diff --git a/src/app/services/hyp3.service.ts b/src/app/services/hyp3.service.ts
index 633f00d63..1aae1ff7d 100644
--- a/src/app/services/hyp3.service.ts
+++ b/src/app/services/hyp3.service.ts
@@ -179,6 +179,7 @@ export class Hyp3Service {
if (a.metadata.date < b.metadata.date) {
return -1;
}
+
return 1;
}));
});
diff --git a/src/app/services/index.ts b/src/app/services/index.ts
index 905448f6e..07ed8c0b1 100644
--- a/src/app/services/index.ts
+++ b/src/app/services/index.ts
@@ -33,3 +33,4 @@ export { SarviewsEventsService } from './sarviews-events.service';
export { BrowseOverlayService } from './browse-overlay.service';
export { ThemingService } from './theming.service';
export { ExportService } from './export.service';
+export { PossibleHyp3JobsService } from './possible-hyp3-jobs.service';
diff --git a/src/app/services/possible-hyp3-jobs.service.ts b/src/app/services/possible-hyp3-jobs.service.ts
new file mode 100644
index 000000000..07b592cd3
--- /dev/null
+++ b/src/app/services/possible-hyp3-jobs.service.ts
@@ -0,0 +1,101 @@
+import { Injectable } from '@angular/core';
+
+import { combineLatest, of } from 'rxjs';
+import { map, switchMap, withLatestFrom } from 'rxjs/operators';
+import { Store } from '@ngrx/store';
+
+import { AppState } from '@store';
+import * as scenesStore from '@store/scenes';
+import * as searchStore from '@store/search';
+
+import * as models from '@models';
+
+import {
+ ScenesService, PairService,
+} from '@services';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class PossibleHyp3JobsService {
+ private products$ = this.scenesService.products$();
+ public pairs$ = this.pairService.pairs$;
+
+ private possibleProductJobs$ = this.products$.pipe(map(
+ products => products.map(p => [p])
+ ));
+
+ private referenceScene$ = this.store$.select(scenesStore.getScenes).pipe(
+ withLatestFrom(this.store$.select(scenesStore.getMasterName)),
+ map(
+ ([scenes, referenceName]) => {
+ if (!!referenceName) {
+ const referenceSceneIdx = scenes.findIndex(scene => scene.name === referenceName);
+
+ if (referenceSceneIdx !== -1) {
+ return scenes[referenceSceneIdx];
+ }
+ }
+ }
+ ));
+
+ private hyp3ableJobsSBAS$ = combineLatest([
+ this.possibleProductJobs$,
+ this.pairs$,
+ ]).pipe(
+ map(([possibleJobs, {pairs, custom}]) => {
+ const allPossiblePairJobs = [...pairs, ...custom];
+
+ return allPossiblePairJobs.concat(possibleJobs);
+ }));
+
+ private hyp3ableJobsBaseline$ = combineLatest([
+ this.products$,
+ this.referenceScene$
+ ]).pipe(
+ map(([products, referenceScene]) => {
+ if (!referenceScene) {
+ return products.map(p => [p]);
+ }
+
+ const baselinePairs = this.makeBaselinePairs(products, referenceScene);
+ return baselinePairs.concat(products.map(p => [p]));
+ })
+ );
+
+ private makeBaselinePairs(products: models.CMRProduct[], referenceScene: models.CMRProduct) {
+ products = products.filter(prod => prod.id !== referenceScene.id);
+
+ const pairedJobs: models.CMRProduct[][] = products.map(product => {
+ return [referenceScene, product]?.sort((a, b) => {
+ if (a.metadata.date < b.metadata.date) {
+ return -1;
+ }
+ return 1;
+ })
+ });
+
+ return pairedJobs;
+ }
+
+ public possibleJobs$ = this.store$.select(searchStore.getSearchType).pipe(
+ switchMap((searchType: models.SearchType) => {
+ if (searchType === models.SearchType.DATASET || searchType === models.SearchType.LIST) {
+ return this.possibleProductJobs$;
+ }
+ else if (searchType === models.SearchType.SBAS) {
+ return this.hyp3ableJobsSBAS$;
+ } else if (searchType === models.SearchType.BASELINE) {
+ return this.hyp3ableJobsBaseline$;
+ } else {
+ return of([]);
+ }
+ })
+ );
+
+ constructor(
+ private store$: Store,
+ private scenesService: ScenesService,
+ private pairService: PairService,
+ ) { }
+}
diff --git a/src/app/services/scenes.service.ts b/src/app/services/scenes.service.ts
index 32f86c65e..b62dfb1de 100644
--- a/src/app/services/scenes.service.ts
+++ b/src/app/services/scenes.service.ts
@@ -41,8 +41,9 @@ export class ScenesService {
this.jobStatusFilter$(
this.filterBaselineValues$(
this.filterByDate$(
+ this.filterBurstSubproducts$(
this.store$.select(getAllProducts)
- ))))))
+ )))))))
);
}
@@ -53,8 +54,9 @@ export class ScenesService {
this.hideS1Raw$(
this.filterBaselineValues$(
this.filterByDate$(
+ this.filterBurstSubproducts$(
this.store$.select(getScenes)
- )))))));
+ ))))))));
public withBrowses$(scenes$: Observable): Observable {
@@ -170,16 +172,30 @@ export class ScenesService {
return scenes
.filter(scene => {
- const statusCode = scene.metadata.job.status_code;
-
- return (
- statuses.has(statusCode)
- );
+ const job = scene.metadata.job;
+ if(!!job) {
+ const statusCode = job.status_code;
+ return statuses.has(statusCode)
+ }
+ return false;
});
})
);
}
+ private filterBurstSubproducts$(scenes$: Observable) {
+ return combineLatest([
+ scenes$,
+ this.store$.select(getSearchType)
+ ]).pipe(
+ map(([scenes, searchtype]) => {
+ if (searchtype === SearchType.CUSTOM_PRODUCTS) {
+ return scenes.filter(scene => scene.productTypeDisplay !== 'XML Metadata (BURST)');
+ }
+ return scenes;
+ })
+ )
+ }
private hideExpired$(scenes$: Observable) {
return combineLatest([
scenes$,
diff --git a/src/app/store/scenes/scenes.reducer.ts b/src/app/store/scenes/scenes.reducer.ts
index 8bb8d4bb9..ae7f8be16 100644
--- a/src/app/store/scenes/scenes.reducer.ts
+++ b/src/app/store/scenes/scenes.reducer.ts
@@ -60,7 +60,7 @@ export const initState: ScenesState = {
perpendicularSort: ColumnSortDirection.NONE,
temporalSort: ColumnSortDirection.NONE,
pinnedProductBrowses: {}
-};
+}
export function scenesReducer(state = initState, action: ScenesActions): ScenesState {
@@ -763,4 +763,4 @@ function eqSet(aSet, bSet): boolean {
function isSubProduct(product): boolean {
return !!product.metadata.parentID;
-}
\ No newline at end of file
+}
diff --git a/src/app/store/search/search.effect.ts b/src/app/store/search/search.effect.ts
index 90ad4e2f7..d7e847e9a 100644
--- a/src/app/store/search/search.effect.ts
+++ b/src/app/store/search/search.effect.ts
@@ -339,11 +339,12 @@ export class SearchEffects {
}
).join(',');
- const collections = this.asfApiService.collections();
-
- return this.asfApiService.query({ 'granule_list': granules, 'collections': collections.join(',') }).pipe(
+ return this.asfApiService.query({ 'granule_list': granules }).pipe(
map(results => this.productService.fromResponse(results)
- .filter(product => !product.metadata.productType.includes('METADATA'))
+ .filter(product => {
+ return !product.metadata.productType.includes('METADATA') ||
+ !product.metadata.productType.includes('BURST_XML');
+ })
.reduce((products, product) => {
products[product.name] = product;
return products;
@@ -363,7 +364,6 @@ export class SearchEffects {
),
catchError(
_ => {
- console.log(_);
return of(new SearchError(`Error loading search results`));
}
),
@@ -417,7 +417,6 @@ export class SearchEffects {
),
catchError(
_ => {
- console.log(_);
return of(new SearchError(`Error loading next batch of On Demand results`));
}
),
@@ -438,6 +437,7 @@ export class SearchEffects {
const virtualProducts = jobs
.filter(job => products[job.job_parameters.granules[0]])
.map(job => {
+
const product = products[job.job_parameters.granules[0]];
const jobFile = !!job.files ?
job.files[0] :
@@ -449,7 +449,7 @@ export class SearchEffects {
job.job_parameters.scenes.push(products[scene_key]);
}
- return {
+ const jobProduct = {
...product,
browses: job.browse_images ? job.browse_images : ['assets/no-browse.png'],
thumbnail: job.thumbnail_images ? job.thumbnail_images[0] : 'assets/no-thumb.png',
@@ -460,11 +460,13 @@ export class SearchEffects {
id: job.job_id,
metadata: {
...product.metadata,
- fileName: jobFile.filename,
+ fileName: jobFile.filename || '',
productType: job.job_type,
job
},
};
+
+ return jobProduct
});
return virtualProducts;