@smarterplan/ngx-smarterplan-core 1.4.17 → 1.4.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/esm2022/lib/components/csv-export/csv-export.component.mjs +3 -3
- package/esm2022/lib/components/loader/loader.component.mjs +3 -3
- package/esm2022/lib/components/menu-bar/avatar/avatar.component.mjs +1 -1
- package/esm2022/lib/components/menu-bar/menu-bar.component.mjs +3 -3
- package/esm2022/lib/components/menu-bar/navigation-bar/navigation-bar.component.mjs +3 -3
- package/esm2022/lib/components/modal-switch-visit/modal-switch-visit.component.mjs +3 -3
- package/esm2022/lib/components/search-bar/search-bar.component.mjs +3 -3
- package/esm2022/lib/components/support-modal/support-modal.component.mjs +3 -3
- package/esm2022/lib/config.mjs +1 -1
- package/esm2022/lib/helpers.service.mjs +1 -1
- package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasImage.mjs +1 -1
- package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasRenderer.mjs +1 -1
- package/esm2022/lib/matterport-extensions/nest-thermostat/NestThermostat.mjs +1 -1
- package/esm2022/lib/matterport-extensions/nest-thermostat/PlaneRenderer.mjs +1 -1
- package/esm2022/lib/matterport-extensions/scene-component/SceneComponent.mjs +1 -1
- package/esm2022/lib/matterport-extensions/security-camera/SecurityCamera.mjs +22 -22
- package/esm2022/lib/matterport-extensions/tv-player/TvPlayer.mjs +1 -1
- package/esm2022/lib/matterport-extensions/view-frustum-mesh/ViewFrustumMesh.mjs +22 -22
- package/esm2022/lib/mattertagData.mjs +10 -1
- package/esm2022/lib/ngx-smarterplan-core.module.mjs +1 -1
- package/esm2022/lib/ngx-smarterplan-core.service.mjs +1 -1
- package/esm2022/lib/pipes/duration-to-string.pipe.mjs +1 -1
- package/esm2022/lib/pipes/format-date-number-to-digits.pipe.mjs +1 -1
- package/esm2022/lib/pipes/hashtag-from-id.pipe.mjs +1 -1
- package/esm2022/lib/pipes/safe-url.pipe.mjs +1 -1
- package/esm2022/lib/pipes/time-date-to-local-string.pipe.mjs +1 -1
- package/esm2022/lib/pipes/username-from-id.pipe.mjs +1 -1
- package/esm2022/lib/services/amplify-cache.service.mjs +1 -1
- package/esm2022/lib/services/base-tab.service.mjs +1 -1
- package/esm2022/lib/services/baseVisibility.service.mjs +1 -1
- package/esm2022/lib/services/content.service.mjs +1 -1
- package/esm2022/lib/services/filter.service.mjs +1 -1
- package/esm2022/lib/services/intervention.service.mjs +1 -1
- package/esm2022/lib/services/locale.service.mjs +1 -1
- package/esm2022/lib/services/matterport-import.service.mjs +10 -3
- package/esm2022/lib/services/matterport-measurement.service.mjs +1 -1
- package/esm2022/lib/services/matterport-navigation.service.mjs +1 -1
- package/esm2022/lib/services/matterport-object3d.service.mjs +1 -1
- package/esm2022/lib/services/matterport-pointer.service.mjs +6 -6
- package/esm2022/lib/services/matterport-tag-copy.service.mjs +455 -9
- package/esm2022/lib/services/matterport-tag.service.mjs +99 -10
- package/esm2022/lib/services/matterport.service.mjs +83 -48
- package/esm2022/lib/services/models/affectation.service.mjs +1 -1
- package/esm2022/lib/services/models/base-object.service.mjs +1 -1
- package/esm2022/lib/services/models/capture.service.mjs +1 -1
- package/esm2022/lib/services/models/comment.service.mjs +1 -1
- package/esm2022/lib/services/models/domain.service.mjs +1 -1
- package/esm2022/lib/services/models/equipment.service.mjs +1 -1
- package/esm2022/lib/services/models/event.service.mjs +1 -1
- package/esm2022/lib/services/models/feature.service.mjs +1 -1
- package/esm2022/lib/services/models/hashtag.service.mjs +1 -1
- package/esm2022/lib/services/models/layer.service.mjs +1 -1
- package/esm2022/lib/services/models/measurement.service.mjs +1 -1
- package/esm2022/lib/services/models/mission.service.mjs +1 -1
- package/esm2022/lib/services/models/navigation.service.mjs +1 -1
- package/esm2022/lib/services/models/node.service.mjs +1 -1
- package/esm2022/lib/services/models/object3D.service.mjs +1 -1
- package/esm2022/lib/services/models/operation.service.mjs +1 -1
- package/esm2022/lib/services/models/organisation.service.mjs +1 -1
- package/esm2022/lib/services/models/plan.service.mjs +1 -1
- package/esm2022/lib/services/models/poi.service.mjs +62 -50
- package/esm2022/lib/services/models/profile.service.mjs +1 -1
- package/esm2022/lib/services/models/property.service.mjs +1 -1
- package/esm2022/lib/services/models/space.service.mjs +1 -1
- package/esm2022/lib/services/models/template.service.mjs +1 -1
- package/esm2022/lib/services/models/ticket.service.mjs +1 -1
- package/esm2022/lib/services/models/visit.service.mjs +1 -1
- package/esm2022/lib/services/models/zone.service.mjs +9 -5
- package/esm2022/lib/services/navigator.service.mjs +1 -1
- package/esm2022/lib/services/s3.service.mjs +1 -1
- package/esm2022/lib/services/search.service.mjs +1 -1
- package/esm2022/lib/services/support.service.mjs +1 -1
- package/esm2022/lib/services/tag.service.mjs +16 -16
- package/esm2022/lib/services/threejs-import.service.mjs +1 -1
- package/esm2022/lib/services/threejs.service.mjs +1 -1
- package/esm2022/lib/services/user.service.mjs +1 -1
- package/esm2022/lib/services/utils/matterport-transform.util.mjs +1 -1
- package/esm2022/lib/services/validators.service.mjs +1 -1
- package/esm2022/lib/services/viewer.service.mjs +1 -1
- package/esm2022/lib/services/zone-drawer.service.mjs +1 -1
- package/esm2022/lib/services/zoneChange.service.mjs +1 -1
- package/esm2022/lib/tokens/matterport-sdk-key.token.mjs +1 -1
- package/esm2022/lib/types.service.mjs +1 -1
- package/esm2022/lib/validators/email.directive.mjs +1 -1
- package/esm2022/lib/validators/no-empty.directive.mjs +1 -1
- package/esm2022/lib/validators/number.directive.mjs +1 -1
- package/esm2022/lib/validators/text.directive.mjs +1 -1
- package/esm2022/public-api.mjs +1 -1
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +793 -193
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
- package/lib/mattertagData.d.ts +4 -0
- package/lib/services/matterport-tag-copy.service.d.ts +128 -2
- package/lib/services/matterport-tag.service.d.ts +24 -1
- package/lib/services/matterport.service.d.ts +12 -3
- package/lib/services/models/poi.service.d.ts +1 -0
- package/package.json +1 -1
- package/src/assets/vs-app.json +67 -67
|
@@ -87,11 +87,11 @@ class CsvExportComponent {
|
|
|
87
87
|
link.remove();
|
|
88
88
|
}
|
|
89
89
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CsvExportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
90
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CsvExportComponent, selector: "lib-csv-export", inputs: { headers: "headers", rowsInput: "rowsInput", getRows: "getRows", title: "title", buttonLabel: "buttonLabel" }, ngImport: i0, template: "<span [style.cursor]=\"'pointer'\" (click)=\"onClickDownload()\" class=\"download-csv d-flex\">\n <span class=\"iconify\" data-icon=\"mdi:file-download-outline\"></span>\n {{ buttonLabel | translate}}\n</span>\n", styles: [".download-csv{color:var(--smarterplan-primary)}\n"], dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
90
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CsvExportComponent, selector: "lib-csv-export", inputs: { headers: "headers", rowsInput: "rowsInput", getRows: "getRows", title: "title", buttonLabel: "buttonLabel" }, ngImport: i0, template: "<span [style.cursor]=\"'pointer'\" (click)=\"onClickDownload()\" class=\"download-csv d-flex\">\r\n <span class=\"iconify\" data-icon=\"mdi:file-download-outline\"></span>\r\n {{ buttonLabel | translate}}\r\n</span>\r\n", styles: [".download-csv{color:var(--smarterplan-primary)}\n"], dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
91
91
|
}
|
|
92
92
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CsvExportComponent, decorators: [{
|
|
93
93
|
type: Component,
|
|
94
|
-
args: [{ selector: 'lib-csv-export', template: "<span [style.cursor]=\"'pointer'\" (click)=\"onClickDownload()\" class=\"download-csv d-flex\">\n <span class=\"iconify\" data-icon=\"mdi:file-download-outline\"></span>\n {{ buttonLabel | translate}}\n</span>\n", styles: [".download-csv{color:var(--smarterplan-primary)}\n"] }]
|
|
94
|
+
args: [{ selector: 'lib-csv-export', template: "<span [style.cursor]=\"'pointer'\" (click)=\"onClickDownload()\" class=\"download-csv d-flex\">\r\n <span class=\"iconify\" data-icon=\"mdi:file-download-outline\"></span>\r\n {{ buttonLabel | translate}}\r\n</span>\r\n", styles: [".download-csv{color:var(--smarterplan-primary)}\n"] }]
|
|
95
95
|
}], propDecorators: { headers: [{
|
|
96
96
|
type: Input
|
|
97
97
|
}], rowsInput: [{
|
|
@@ -795,30 +795,30 @@ class SecurityCamera extends SceneComponent {
|
|
|
795
795
|
}
|
|
796
796
|
}
|
|
797
797
|
function vertexShader$1() {
|
|
798
|
-
return `
|
|
799
|
-
uniform mat4 lightMatrix;
|
|
800
|
-
|
|
801
|
-
varying vec4 vLightCoords;
|
|
802
|
-
|
|
803
|
-
void main() {
|
|
804
|
-
// create a UV region [0,1] x [0,1] to represent what the lightMatrix "sees"
|
|
805
|
-
vLightCoords = lightMatrix * modelMatrix * vec4(position, 1.0);
|
|
806
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
807
|
-
}
|
|
798
|
+
return `
|
|
799
|
+
uniform mat4 lightMatrix;
|
|
800
|
+
|
|
801
|
+
varying vec4 vLightCoords;
|
|
802
|
+
|
|
803
|
+
void main() {
|
|
804
|
+
// create a UV region [0,1] x [0,1] to represent what the lightMatrix "sees"
|
|
805
|
+
vLightCoords = lightMatrix * modelMatrix * vec4(position, 1.0);
|
|
806
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
807
|
+
}
|
|
808
808
|
`;
|
|
809
809
|
}
|
|
810
810
|
function fragmentShader$1() {
|
|
811
|
-
return `
|
|
812
|
-
uniform vec3 color;
|
|
813
|
-
|
|
814
|
-
varying vec4 vLightCoords;
|
|
815
|
-
|
|
816
|
-
void main() {
|
|
817
|
-
vec2 lightUV = vLightCoords.xy / vLightCoords.w;
|
|
818
|
-
float inView = float(max(lightUV.x, lightUV.y) <= 1.0 && min(lightUV.x, lightUV.y) >= 0.0 && vLightCoords.z > 0.0);
|
|
819
|
-
|
|
820
|
-
gl_FragColor = vec4(color, min(inView, 0.2));
|
|
821
|
-
}
|
|
811
|
+
return `
|
|
812
|
+
uniform vec3 color;
|
|
813
|
+
|
|
814
|
+
varying vec4 vLightCoords;
|
|
815
|
+
|
|
816
|
+
void main() {
|
|
817
|
+
vec2 lightUV = vLightCoords.xy / vLightCoords.w;
|
|
818
|
+
float inView = float(max(lightUV.x, lightUV.y) <= 1.0 && min(lightUV.x, lightUV.y) >= 0.0 && vLightCoords.z > 0.0);
|
|
819
|
+
|
|
820
|
+
gl_FragColor = vec4(color, min(inView, 0.2));
|
|
821
|
+
}
|
|
822
822
|
`;
|
|
823
823
|
}
|
|
824
824
|
function updateHighlightUniforms$1(projector, uniforms) {
|
|
@@ -1011,30 +1011,30 @@ class ViewFrustumMesh extends SceneComponent {
|
|
|
1011
1011
|
}
|
|
1012
1012
|
}
|
|
1013
1013
|
function vertexShader() {
|
|
1014
|
-
return `
|
|
1015
|
-
uniform mat4 lightMatrix;
|
|
1016
|
-
|
|
1017
|
-
varying vec4 vLightCoords;
|
|
1018
|
-
|
|
1019
|
-
void main() {
|
|
1020
|
-
// create a UV region [0,1] x [0,1] to represent what the lightMatrix "sees"
|
|
1021
|
-
vLightCoords = lightMatrix * modelMatrix * vec4(position, 1.0);
|
|
1022
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
1023
|
-
}
|
|
1014
|
+
return `
|
|
1015
|
+
uniform mat4 lightMatrix;
|
|
1016
|
+
|
|
1017
|
+
varying vec4 vLightCoords;
|
|
1018
|
+
|
|
1019
|
+
void main() {
|
|
1020
|
+
// create a UV region [0,1] x [0,1] to represent what the lightMatrix "sees"
|
|
1021
|
+
vLightCoords = lightMatrix * modelMatrix * vec4(position, 1.0);
|
|
1022
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
1023
|
+
}
|
|
1024
1024
|
`;
|
|
1025
1025
|
}
|
|
1026
1026
|
function fragmentShader() {
|
|
1027
|
-
return `
|
|
1028
|
-
uniform vec3 color;
|
|
1029
|
-
|
|
1030
|
-
varying vec4 vLightCoords;
|
|
1031
|
-
|
|
1032
|
-
void main() {
|
|
1033
|
-
vec2 lightUV = vLightCoords.xy / vLightCoords.w;
|
|
1034
|
-
float inView = float(max(lightUV.x, lightUV.y) <= 1.0 && min(lightUV.x, lightUV.y) >= 0.0 && vLightCoords.z > 0.0);
|
|
1035
|
-
|
|
1036
|
-
gl_FragColor = vec4(color, min(inView, 0.2));
|
|
1037
|
-
}
|
|
1027
|
+
return `
|
|
1028
|
+
uniform vec3 color;
|
|
1029
|
+
|
|
1030
|
+
varying vec4 vLightCoords;
|
|
1031
|
+
|
|
1032
|
+
void main() {
|
|
1033
|
+
vec2 lightUV = vLightCoords.xy / vLightCoords.w;
|
|
1034
|
+
float inView = float(max(lightUV.x, lightUV.y) <= 1.0 && min(lightUV.x, lightUV.y) >= 0.0 && vLightCoords.z > 0.0);
|
|
1035
|
+
|
|
1036
|
+
gl_FragColor = vec4(color, min(inView, 0.2));
|
|
1037
|
+
}
|
|
1038
1038
|
`;
|
|
1039
1039
|
}
|
|
1040
1040
|
function updateHighlightUniforms(projector, uniforms) {
|
|
@@ -2197,66 +2197,78 @@ class PoiService {
|
|
|
2197
2197
|
if (!sweeps || sweeps.length === 0) {
|
|
2198
2198
|
return [];
|
|
2199
2199
|
}
|
|
2200
|
-
const queryStatement = `
|
|
2201
|
-
query ListPOISLight($filter: ModelPOIFilterInput, $limit: Int, $nextToken: String) {
|
|
2202
|
-
listPOIS(filter: $filter, limit: $limit, nextToken: $nextToken) {
|
|
2203
|
-
items {
|
|
2204
|
-
id
|
|
2205
|
-
coordinate
|
|
2206
|
-
specific
|
|
2207
|
-
private
|
|
2208
|
-
global
|
|
2209
|
-
type
|
|
2210
|
-
elementID
|
|
2211
|
-
level
|
|
2212
|
-
role
|
|
2213
|
-
category
|
|
2214
|
-
domainID
|
|
2215
|
-
metadata
|
|
2216
|
-
tagIcon
|
|
2217
|
-
tagDescription
|
|
2218
|
-
tagImageID
|
|
2219
|
-
matterportSweepID
|
|
2220
|
-
createdAt
|
|
2221
|
-
updatedAt
|
|
2222
|
-
}
|
|
2223
|
-
nextToken
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2200
|
+
const queryStatement = `
|
|
2201
|
+
query ListPOISLight($filter: ModelPOIFilterInput, $limit: Int, $nextToken: String) {
|
|
2202
|
+
listPOIS(filter: $filter, limit: $limit, nextToken: $nextToken) {
|
|
2203
|
+
items {
|
|
2204
|
+
id
|
|
2205
|
+
coordinate
|
|
2206
|
+
specific
|
|
2207
|
+
private
|
|
2208
|
+
global
|
|
2209
|
+
type
|
|
2210
|
+
elementID
|
|
2211
|
+
level
|
|
2212
|
+
role
|
|
2213
|
+
category
|
|
2214
|
+
domainID
|
|
2215
|
+
metadata
|
|
2216
|
+
tagIcon
|
|
2217
|
+
tagDescription
|
|
2218
|
+
tagImageID
|
|
2219
|
+
matterportSweepID
|
|
2220
|
+
createdAt
|
|
2221
|
+
updatedAt
|
|
2222
|
+
}
|
|
2223
|
+
nextToken
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
2226
|
`;
|
|
2227
2227
|
const CHUNK_SIZE = 50; // safe margin for an "or" filter expression's practical size
|
|
2228
2228
|
const chunks = [];
|
|
2229
2229
|
for (let i = 0; i < sweeps.length; i += CHUNK_SIZE) {
|
|
2230
2230
|
chunks.push(sweeps.slice(i, i + CHUNK_SIZE));
|
|
2231
2231
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2232
|
+
// Each chunk is a full table Scan of its own: running them in parallel instead of one after
|
|
2233
|
+
// the other divides the wait by the number of chunks (7.6 s -> ~1 s on a 456-sweep space).
|
|
2234
|
+
// Results are flattened in chunk order, so the output is the same as the sequential version.
|
|
2235
|
+
const results = await Promise.all(chunks.map(chunk => this.scanPoisForSweepChunk(queryStatement, chunk)));
|
|
2236
|
+
return results.flat();
|
|
2237
|
+
}
|
|
2238
|
+
async scanPoisForSweepChunk(queryStatement, chunk) {
|
|
2239
|
+
const pois = [];
|
|
2240
|
+
let nextToken = null;
|
|
2241
|
+
do {
|
|
2242
|
+
const variables = {
|
|
2243
|
+
filter: {
|
|
2244
|
+
or: chunk.map((sweep) => ({ matterportSweepID: { eq: sweep } }))
|
|
2245
|
+
},
|
|
2246
|
+
limit: 1000,
|
|
2247
|
+
nextToken
|
|
2248
|
+
};
|
|
2249
|
+
// A failed page is retried once: giving up at once silently dropped the rest of the
|
|
2250
|
+
// chunk (up to 50 sweeps worth of POIs) from the copy or recalibration lists.
|
|
2251
|
+
let resData = null;
|
|
2252
|
+
for (let attempt = 1; attempt <= 2 && !resData; attempt++) {
|
|
2243
2253
|
try {
|
|
2244
2254
|
const response = (await API.graphql(graphqlOperation(queryStatement, variables)));
|
|
2245
|
-
|
|
2246
|
-
if (resData && resData.items.length > 0) {
|
|
2247
|
-
allPois = [...allPois, ...resData.items];
|
|
2248
|
-
}
|
|
2249
|
-
nextToken = resData?.nextToken ?? null;
|
|
2255
|
+
resData = response.data.listPOIS ?? { items: [], nextToken: null };
|
|
2250
2256
|
}
|
|
2251
2257
|
catch (error) {
|
|
2252
|
-
//
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2258
|
+
// Amplify rejects when one item errors but still hands over the readable ones
|
|
2259
|
+
if (error?.data?.listPOIS) {
|
|
2260
|
+
resData = error.data.listPOIS;
|
|
2261
|
+
}
|
|
2262
|
+
else if (attempt === 2) {
|
|
2263
|
+
// the rest of the process continues with whatever was already collected
|
|
2264
|
+
console.error(`Error while fetching POIs for a sweep chunk:`, error);
|
|
2265
|
+
}
|
|
2256
2266
|
}
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
|
-
|
|
2267
|
+
}
|
|
2268
|
+
pois.push(...(resData?.items || []).filter((poi) => !!poi));
|
|
2269
|
+
nextToken = resData?.nextToken ?? null;
|
|
2270
|
+
} while (nextToken);
|
|
2271
|
+
return pois;
|
|
2260
2272
|
}
|
|
2261
2273
|
unsubscribe() {
|
|
2262
2274
|
this.destroy$.next(true);
|
|
@@ -2345,6 +2357,15 @@ class MattertagData {
|
|
|
2345
2357
|
color: { r: 1, g: 1, b: 1 },
|
|
2346
2358
|
};
|
|
2347
2359
|
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Safely retrieves the display name depending on object properties (name, title)
|
|
2362
|
+
*/
|
|
2363
|
+
getDisplayName() {
|
|
2364
|
+
if (!this.object) {
|
|
2365
|
+
return '';
|
|
2366
|
+
}
|
|
2367
|
+
return this.object.name || this.object.title || '';
|
|
2368
|
+
}
|
|
2348
2369
|
/**
|
|
2349
2370
|
* Get the descriptor for sdk.Tag.add(...descriptor)
|
|
2350
2371
|
* Format : [{ label, description, anchorPosition, stemVector, color, id? }]
|
|
@@ -2989,11 +3010,11 @@ class MatterportPointerService {
|
|
|
2989
3010
|
}
|
|
2990
3011
|
updateCursorDisplay(poseMatterport) {
|
|
2991
3012
|
if (this.textDisplayCursorPositionPanel && poseMatterport) {
|
|
2992
|
-
this.textDisplayCursorPositionPanel.innerHTML = `position:
|
|
2993
|
-
${pointToString(poseMatterport.position)}\n
|
|
2994
|
-
normal:
|
|
2995
|
-
${pointToString(poseMatterport.normal)}\n
|
|
2996
|
-
floorId:
|
|
3013
|
+
this.textDisplayCursorPositionPanel.innerHTML = `position:
|
|
3014
|
+
${pointToString(poseMatterport.position)}\n
|
|
3015
|
+
normal:
|
|
3016
|
+
${pointToString(poseMatterport.normal)}\n
|
|
3017
|
+
floorId:
|
|
2997
3018
|
${poseMatterport.floorId}`;
|
|
2998
3019
|
if (this.getCursorPositionButton) {
|
|
2999
3020
|
this.getCursorPositionButton.style.display = 'none';
|
|
@@ -3653,6 +3674,13 @@ class MatterportTagService {
|
|
|
3653
3674
|
tagService = null;
|
|
3654
3675
|
tagsCurrentOpacity = new Map();
|
|
3655
3676
|
tagsCurrentEnabled = new Map();
|
|
3677
|
+
/** tagId -> icon name last applied, so an unchanged icon is not re-applied. */
|
|
3678
|
+
tagsCurrentIcon = new Map();
|
|
3679
|
+
/** Ids of the global SDK Tag collection, and the tags waiting to appear in it, see waitForTagInSdk(). */
|
|
3680
|
+
sdkTagIds = new Set();
|
|
3681
|
+
sdkTagWaiters = new Map();
|
|
3682
|
+
sdkTagSubscription = null;
|
|
3683
|
+
sdkTagSubscriptionSdk = null;
|
|
3656
3684
|
/**
|
|
3657
3685
|
* Single layer holding every Smarterplan tag, added to every view of the space so a
|
|
3658
3686
|
* tag stays in place — same sid, same content — when the user switches between the
|
|
@@ -3696,11 +3724,92 @@ class MatterportTagService {
|
|
|
3696
3724
|
* A layer-scoped Tag module only exposes the *replayable* mutations, meant to build
|
|
3697
3725
|
* the layer's own content; applying them to an already-created tag silently does
|
|
3698
3726
|
* nothing — which is what left every pin white instead of carrying its icon. Only
|
|
3699
|
-
* `add` has to go through the layer, see getTagCreationModule().
|
|
3727
|
+
* `add` has to go through the layer, see getTagCreationModule(). The global module
|
|
3728
|
+
* only knows a layer-created pin once it is rendered: see waitForTagInSdk().
|
|
3700
3729
|
*/
|
|
3701
3730
|
getTagModule(sdk, tagId) {
|
|
3702
3731
|
return sdk?.Tag;
|
|
3703
3732
|
}
|
|
3733
|
+
/** Icon name last applied to a tag, if any. */
|
|
3734
|
+
getCachedTagIcon(tagId) {
|
|
3735
|
+
return this.tagsCurrentIcon.get(tagId);
|
|
3736
|
+
}
|
|
3737
|
+
/** Applies an icon to a tag through its own module and remembers it on success. */
|
|
3738
|
+
async editTagIcon(sdk, tagId, iconName) {
|
|
3739
|
+
await this.getTagModule(sdk, tagId).editIcon(tagId, iconName);
|
|
3740
|
+
this.tagsCurrentIcon.set(tagId, iconName);
|
|
3741
|
+
}
|
|
3742
|
+
/**
|
|
3743
|
+
* Resolves once the global SDK Tag collection — the one edits go through — contains the
|
|
3744
|
+
* tag, so edits do not hit a pin that is not rendered yet ("setPinRenderOverrides on a pin
|
|
3745
|
+
* that doesn't exist"). Gives up after `timeoutMs` and resolves anyway; falls back to a
|
|
3746
|
+
* short wait when the collection cannot be observed. One subscription is shared by every
|
|
3747
|
+
* waiting tag: a space loads hundreds of them.
|
|
3748
|
+
*/
|
|
3749
|
+
waitForTagInSdk(sdk, tagId, timeoutMs = 1500) {
|
|
3750
|
+
if (!tagId || !this.observeSdkTags(sdk))
|
|
3751
|
+
return wait(100);
|
|
3752
|
+
if (this.sdkTagIds.has(tagId))
|
|
3753
|
+
return Promise.resolve();
|
|
3754
|
+
return new Promise((resolve) => {
|
|
3755
|
+
const waiters = this.sdkTagWaiters.get(tagId) || [];
|
|
3756
|
+
const timer = setTimeout(() => {
|
|
3757
|
+
const remaining = (this.sdkTagWaiters.get(tagId) || []).filter(waiter => waiter !== done);
|
|
3758
|
+
if (remaining.length)
|
|
3759
|
+
this.sdkTagWaiters.set(tagId, remaining);
|
|
3760
|
+
else
|
|
3761
|
+
this.sdkTagWaiters.delete(tagId);
|
|
3762
|
+
resolve();
|
|
3763
|
+
}, timeoutMs);
|
|
3764
|
+
const done = () => { clearTimeout(timer); resolve(); };
|
|
3765
|
+
waiters.push(done);
|
|
3766
|
+
this.sdkTagWaiters.set(tagId, waiters);
|
|
3767
|
+
});
|
|
3768
|
+
}
|
|
3769
|
+
/** Keeps sdkTagIds in sync with the global SDK Tag collection; false when it cannot be observed. */
|
|
3770
|
+
observeSdkTags(sdk) {
|
|
3771
|
+
if (this.sdkTagSubscription && this.sdkTagSubscriptionSdk === sdk)
|
|
3772
|
+
return true;
|
|
3773
|
+
const data = sdk?.Tag?.data;
|
|
3774
|
+
if (typeof data?.subscribe !== 'function')
|
|
3775
|
+
return false;
|
|
3776
|
+
this.stopObservingSdkTags();
|
|
3777
|
+
const markPresent = (id) => {
|
|
3778
|
+
this.sdkTagIds.add(id);
|
|
3779
|
+
const waiters = this.sdkTagWaiters.get(id);
|
|
3780
|
+
if (waiters) {
|
|
3781
|
+
this.sdkTagWaiters.delete(id);
|
|
3782
|
+
waiters.forEach(waiter => waiter());
|
|
3783
|
+
}
|
|
3784
|
+
};
|
|
3785
|
+
try {
|
|
3786
|
+
this.sdkTagSubscriptionSdk = sdk;
|
|
3787
|
+
this.sdkTagSubscription = data.subscribe({
|
|
3788
|
+
onAdded: (id) => markPresent(id),
|
|
3789
|
+
onRemoved: (id) => this.sdkTagIds.delete(id),
|
|
3790
|
+
onCollectionUpdated: (collection) => {
|
|
3791
|
+
const ids = typeof collection?.keys === 'function'
|
|
3792
|
+
? Array.from(collection.keys()) : Object.keys(collection || {});
|
|
3793
|
+
this.sdkTagIds = new Set(ids);
|
|
3794
|
+
ids.forEach(id => this.sdkTagWaiters.has(id) && markPresent(id));
|
|
3795
|
+
},
|
|
3796
|
+
});
|
|
3797
|
+
return true;
|
|
3798
|
+
}
|
|
3799
|
+
catch {
|
|
3800
|
+
this.sdkTagSubscriptionSdk = null;
|
|
3801
|
+
return false;
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
stopObservingSdkTags() {
|
|
3805
|
+
try {
|
|
3806
|
+
this.sdkTagSubscription?.cancel?.();
|
|
3807
|
+
}
|
|
3808
|
+
catch { }
|
|
3809
|
+
this.sdkTagSubscription = null;
|
|
3810
|
+
this.sdkTagSubscriptionSdk = null;
|
|
3811
|
+
this.sdkTagIds.clear();
|
|
3812
|
+
}
|
|
3704
3813
|
/**
|
|
3705
3814
|
* Returns the Tag module every new tag must be created through: the shared layer
|
|
3706
3815
|
* when the View API is available, the global sdk.Tag otherwise.
|
|
@@ -3855,7 +3964,7 @@ class MatterportTagService {
|
|
|
3855
3964
|
const [createdSid] = await tagModule.add(...descriptor);
|
|
3856
3965
|
this.mattertagIDs.push(createdSid);
|
|
3857
3966
|
this.dictionnaryTags.set(createdSid, mattertagData);
|
|
3858
|
-
await
|
|
3967
|
+
await this.waitForTagInSdk(sdk, createdSid);
|
|
3859
3968
|
await setTagIconAndOpacity(createdSid, mattertagData);
|
|
3860
3969
|
injectHtmlInTag(mattertagData.getType(), mattertagData.getObject(), createdSid).catch(err => {
|
|
3861
3970
|
if (isDevMode())
|
|
@@ -3976,6 +4085,7 @@ class MatterportTagService {
|
|
|
3976
4085
|
resetVisibilityCache() {
|
|
3977
4086
|
this.tagsCurrentOpacity.clear();
|
|
3978
4087
|
this.tagsCurrentEnabled.clear();
|
|
4088
|
+
this.tagsCurrentIcon.clear();
|
|
3979
4089
|
}
|
|
3980
4090
|
/** Removes a specific tag from the viewer and local dictionaries. */
|
|
3981
4091
|
async deleteMattertagFromId(sdk, mattertagID) {
|
|
@@ -3983,6 +4093,9 @@ class MatterportTagService {
|
|
|
3983
4093
|
if (sdk)
|
|
3984
4094
|
await this.getTagModule(sdk, mattertagID).remove(mattertagID);
|
|
3985
4095
|
this.dictionnaryTags.delete(mattertagID);
|
|
4096
|
+
this.tagsCurrentIcon.delete(mattertagID);
|
|
4097
|
+
this.tagsCurrentOpacity.delete(mattertagID);
|
|
4098
|
+
this.tagsCurrentEnabled.delete(mattertagID);
|
|
3986
4099
|
const index = this.mattertagIDs.indexOf(mattertagID);
|
|
3987
4100
|
if (index > -1)
|
|
3988
4101
|
this.mattertagIDs.splice(index, 1);
|
|
@@ -4044,14 +4157,8 @@ class MatterportTagService {
|
|
|
4044
4157
|
}
|
|
4045
4158
|
mattertagData.setPoi(poi);
|
|
4046
4159
|
const createdTagID = await this.addMattertagToViewer(sdk, mattertagData);
|
|
4047
|
-
console.log('---------------');
|
|
4048
|
-
console.log('element id ' + mattertagData.elementID);
|
|
4049
|
-
console.log('position: ', mattertagData.getPosition());
|
|
4050
|
-
console.log('rotation: ', mattertagData.getRotation());
|
|
4051
|
-
console.log('sweep id: ', mattertagData.getSweepID());
|
|
4052
|
-
console.log('---------------');
|
|
4053
4160
|
if (createdTagID && sdk) {
|
|
4054
|
-
await
|
|
4161
|
+
await this.waitForTagInSdk(sdk, createdTagID);
|
|
4055
4162
|
await setTagIconAndOpacity(createdTagID, mattertagData);
|
|
4056
4163
|
injectHtmlInTag(tagType, object, createdTagID).catch(err => {
|
|
4057
4164
|
if (isDevMode())
|
|
@@ -4080,6 +4187,7 @@ class MatterportTagService {
|
|
|
4080
4187
|
const tagModule = this.getTagModule(sdk, mattertagID);
|
|
4081
4188
|
await sdk.Asset.registerTexture(iconName, iconPath);
|
|
4082
4189
|
await tagModule.editIcon(mattertagID, iconName);
|
|
4190
|
+
this.tagsCurrentIcon.set(mattertagID, iconName);
|
|
4083
4191
|
if (applyOpacity) {
|
|
4084
4192
|
await tagModule.editOpacity(mattertagID, opacity);
|
|
4085
4193
|
}
|
|
@@ -4209,6 +4317,8 @@ class MatterportTagService {
|
|
|
4209
4317
|
this.dictionnaryTags.clear();
|
|
4210
4318
|
this.tagsCurrentOpacity.clear();
|
|
4211
4319
|
this.tagsCurrentEnabled.clear();
|
|
4320
|
+
this.tagsCurrentIcon.clear();
|
|
4321
|
+
this.stopObservingSdkTags();
|
|
4212
4322
|
this.tagAddQueue = Promise.resolve();
|
|
4213
4323
|
this.mattertagToFollow = null;
|
|
4214
4324
|
this.mattertagIDs = [];
|
|
@@ -4332,6 +4442,12 @@ class MatterportService {
|
|
|
4332
4442
|
tagAction = new Subject();
|
|
4333
4443
|
/** Views (furnished, defurnished...) exposed by the SDK for the current space. */
|
|
4334
4444
|
viewsByType = new Map();
|
|
4445
|
+
/** Settles once every static icon texture has been registered (or failed). */
|
|
4446
|
+
iconsRegistered = Promise.resolve();
|
|
4447
|
+
/** Names of the textures successfully registered in the current SDK session. */
|
|
4448
|
+
registeredIcons = new Set();
|
|
4449
|
+
/** tagId -> signed source last registered as a custom texture, and its texture name. */
|
|
4450
|
+
customIconCache = new Map();
|
|
4335
4451
|
currentView = null;
|
|
4336
4452
|
viewSubscriptions = [];
|
|
4337
4453
|
/** Emits the active view every time the user switches between furnished/defurnished. */
|
|
@@ -4460,13 +4576,16 @@ class MatterportService {
|
|
|
4460
4576
|
this.addCustomCss();
|
|
4461
4577
|
this.pointerService.startAdminCursorTracker(this.sdk, this.container, () => this.poseMatterport, () => this.poseCamera);
|
|
4462
4578
|
// Load Mattertag icons and custom subscriptions
|
|
4579
|
+
this.registeredIcons.clear();
|
|
4580
|
+
this.customIconCache.clear();
|
|
4581
|
+
const iconRegistrations = [];
|
|
4463
4582
|
switch (module) {
|
|
4464
4583
|
case SpModule.IMMO:
|
|
4465
|
-
this.
|
|
4466
|
-
this.
|
|
4467
|
-
this.
|
|
4468
|
-
this.
|
|
4469
|
-
this.
|
|
4584
|
+
iconRegistrations.push(this.registerIcon('icon-ticket', this.config.my_config.icon_ticket));
|
|
4585
|
+
iconRegistrations.push(this.registerIcon('icon-equipment', this.config.my_config.icon_equipment));
|
|
4586
|
+
iconRegistrations.push(this.registerIcon('icon-measure', this.config.my_config.icon_measure));
|
|
4587
|
+
iconRegistrations.push(this.registerIcon('icon-data', this.config.my_config.icon_data));
|
|
4588
|
+
iconRegistrations.push(this.registerIcon('icon-object3d', this.config.my_config.icon_object3d));
|
|
4470
4589
|
this.sdk.Measurements.data.subscribe({
|
|
4471
4590
|
onAdded: function (index, item, collection) {
|
|
4472
4591
|
this.measurementService.setLastMeasure(item.points);
|
|
@@ -4483,20 +4602,19 @@ class MatterportService {
|
|
|
4483
4602
|
}.bind(this));
|
|
4484
4603
|
break;
|
|
4485
4604
|
case SpModule.MUSEUM:
|
|
4486
|
-
this.
|
|
4605
|
+
iconRegistrations.push(this.registerIcon('icon-data', this.config.my_config.icon_data));
|
|
4487
4606
|
break;
|
|
4488
4607
|
case SpModule.HOTEL:
|
|
4489
|
-
this.
|
|
4490
|
-
this.
|
|
4491
|
-
this.
|
|
4492
|
-
this.
|
|
4608
|
+
iconRegistrations.push(this.registerIcon('icon_room_available', this.config.my_config.icon_room_available));
|
|
4609
|
+
iconRegistrations.push(this.registerIcon('icon_room_unavailable', this.config.my_config.icon_room_unavailable));
|
|
4610
|
+
iconRegistrations.push(this.registerIcon('icon_room_chosen', this.config.my_config.icon_room_chosen));
|
|
4611
|
+
iconRegistrations.push(this.registerIcon('icon_room_viewed', this.config.my_config.icon_room_viewed));
|
|
4493
4612
|
break;
|
|
4494
4613
|
default:
|
|
4495
4614
|
break;
|
|
4496
4615
|
}
|
|
4497
|
-
this.
|
|
4498
|
-
|
|
4499
|
-
console.warn('icon-position texture registration failed', e); });
|
|
4616
|
+
iconRegistrations.push(this.registerIcon('icon-position', this.config.my_config.icon_position));
|
|
4617
|
+
this.iconsRegistered = Promise.allSettled(iconRegistrations).then(() => undefined);
|
|
4500
4618
|
// Current Room (used for getting bounding box and eventually lazy load mattertag or object3D inside current Room)
|
|
4501
4619
|
this.sdk.Room.current.subscribe((currentRoom) => {
|
|
4502
4620
|
const rooms = Array.isArray(currentRoom) ? currentRoom : (currentRoom ? [currentRoom] : []);
|
|
@@ -4854,15 +4972,29 @@ class MatterportService {
|
|
|
4854
4972
|
/** Applies a pre-registered icon to a Mattertag. */
|
|
4855
4973
|
async setRegistredIconForTag(mattertagID, iconName) {
|
|
4856
4974
|
try {
|
|
4857
|
-
this.matterportTagService.
|
|
4975
|
+
await this.matterportTagService.editTagIcon(this.sdk, mattertagID, iconName);
|
|
4858
4976
|
}
|
|
4859
4977
|
catch (e) {
|
|
4860
4978
|
if (isDevMode())
|
|
4861
4979
|
console.warn('Could not edit icon', iconName, e);
|
|
4862
4980
|
}
|
|
4863
4981
|
}
|
|
4864
|
-
/**
|
|
4982
|
+
/** Registers a static texture and remembers its name once the SDK accepted it. */
|
|
4983
|
+
async registerIcon(iconName, iconPath) {
|
|
4984
|
+
if (!iconPath)
|
|
4985
|
+
return;
|
|
4986
|
+
try {
|
|
4987
|
+
await this.sdk.Asset.registerTexture(iconName, iconPath);
|
|
4988
|
+
this.registeredIcons.add(iconName);
|
|
4989
|
+
}
|
|
4990
|
+
catch (e) {
|
|
4991
|
+
if (isDevMode())
|
|
4992
|
+
console.warn(`[MatterportService] ${iconName} texture registration failed`, e);
|
|
4993
|
+
}
|
|
4994
|
+
}
|
|
4995
|
+
/** Sets the appropriate icon for a tag based on its type and POI metadata. */
|
|
4865
4996
|
async setTagIconAndOpacity(mattertagID, mattertagData) {
|
|
4997
|
+
await this.iconsRegistered;
|
|
4866
4998
|
if (this.SPModule === SpModule.HOTEL) {
|
|
4867
4999
|
const room = mattertagData.getObject();
|
|
4868
5000
|
let iconName = `icon_room`;
|
|
@@ -4876,7 +5008,6 @@ class MatterportService {
|
|
|
4876
5008
|
return;
|
|
4877
5009
|
}
|
|
4878
5010
|
const stringTagType = poiTypeToString(mattertagData.getType());
|
|
4879
|
-
let opacity = this.config.my_config.DEFAULT_OPACITY_TAG;
|
|
4880
5011
|
let iconName = `icon-${stringTagType}`;
|
|
4881
5012
|
const poi = mattertagData.getPoi();
|
|
4882
5013
|
if (poi && poi.tagIcon) {
|
|
@@ -4888,31 +5019,45 @@ class MatterportService {
|
|
|
4888
5019
|
}
|
|
4889
5020
|
}
|
|
4890
5021
|
if (tagIcon.src) {
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
5022
|
+
// keyed on the stored source, not on the signed URL: a new signature every call
|
|
5023
|
+
const cached = this.customIconCache.get(mattertagID);
|
|
5024
|
+
if (cached && cached.src === tagIcon.src) {
|
|
5025
|
+
iconName = cached.iconName;
|
|
5026
|
+
}
|
|
5027
|
+
else {
|
|
5028
|
+
const pathSigned = await this.tagService.getSignedTagIconSource(tagIcon.src);
|
|
5029
|
+
if (pathSigned) {
|
|
5030
|
+
try {
|
|
5031
|
+
const customIconName = `icon-${stringTagType}-${mattertagID}-${mattertagData.customIconIndex}`;
|
|
5032
|
+
await this.sdk.Asset.registerTexture(customIconName, pathSigned);
|
|
5033
|
+
mattertagData.customIconIndex += 1;
|
|
5034
|
+
this.customIconCache.set(mattertagID, { src: tagIcon.src, iconName: customIconName });
|
|
5035
|
+
this.registeredIcons.add(customIconName);
|
|
5036
|
+
iconName = customIconName;
|
|
5037
|
+
}
|
|
5038
|
+
catch {
|
|
5039
|
+
console.log('error registerIcon');
|
|
5040
|
+
}
|
|
4900
5041
|
}
|
|
4901
5042
|
}
|
|
4902
5043
|
}
|
|
4903
|
-
if (tagIcon.opacity) {
|
|
4904
|
-
opacity = tagIcon.opacity;
|
|
4905
|
-
}
|
|
4906
5044
|
}
|
|
4907
5045
|
await this.editTagIcon(mattertagID, iconName);
|
|
4908
5046
|
}
|
|
4909
5047
|
/**
|
|
4910
|
-
* Applies an icon to a tag
|
|
4911
|
-
* silently dropped promise here leaves the pin
|
|
5048
|
+
* Applies an icon to a tag, unless that icon is already the one applied. The call is
|
|
5049
|
+
* awaited and its rejection reported: a silently dropped promise here leaves the pin
|
|
5050
|
+
* with its default white look.
|
|
4912
5051
|
*/
|
|
4913
5052
|
async editTagIcon(mattertagID, iconName) {
|
|
5053
|
+
if (this.matterportTagService.getCachedTagIcon(mattertagID) === iconName)
|
|
5054
|
+
return;
|
|
5055
|
+
// A texture that was never registered (no icon configured for this type) can only fail:
|
|
5056
|
+
// the pin keeps its default look, as before, without a doomed SDK call.
|
|
5057
|
+
if (!this.registeredIcons.has(iconName))
|
|
5058
|
+
return;
|
|
4914
5059
|
try {
|
|
4915
|
-
await this.matterportTagService.
|
|
5060
|
+
await this.matterportTagService.editTagIcon(this.sdk, mattertagID, iconName);
|
|
4916
5061
|
}
|
|
4917
5062
|
catch (error) {
|
|
4918
5063
|
if (isDevMode())
|
|
@@ -5015,22 +5160,22 @@ class MatterportService {
|
|
|
5015
5160
|
);
|
|
5016
5161
|
}*/
|
|
5017
5162
|
addCustomCss() {
|
|
5018
|
-
const css = `
|
|
5019
|
-
.footer-ui,
|
|
5020
|
-
.showcase-footer,
|
|
5021
|
-
.mp-nova-btn-group,
|
|
5022
|
-
.footer-divider,
|
|
5023
|
-
.logo-link,
|
|
5024
|
-
.footer-logo,
|
|
5025
|
-
.bottom-ui,
|
|
5026
|
-
img.logo-image,
|
|
5027
|
-
img[class^="logo-image"],
|
|
5028
|
-
img[class*=" logo-image"],
|
|
5029
|
-
[data-testid="showcase-footer"] {
|
|
5030
|
-
opacity: 0 !important;
|
|
5031
|
-
visibility: hidden !important;
|
|
5032
|
-
pointer-events: none !important;
|
|
5033
|
-
}
|
|
5163
|
+
const css = `
|
|
5164
|
+
.footer-ui,
|
|
5165
|
+
.showcase-footer,
|
|
5166
|
+
.mp-nova-btn-group,
|
|
5167
|
+
.footer-divider,
|
|
5168
|
+
.logo-link,
|
|
5169
|
+
.footer-logo,
|
|
5170
|
+
.bottom-ui,
|
|
5171
|
+
img.logo-image,
|
|
5172
|
+
img[class^="logo-image"],
|
|
5173
|
+
img[class*=" logo-image"],
|
|
5174
|
+
[data-testid="showcase-footer"] {
|
|
5175
|
+
opacity: 0 !important;
|
|
5176
|
+
visibility: hidden !important;
|
|
5177
|
+
pointer-events: none !important;
|
|
5178
|
+
}
|
|
5034
5179
|
`;
|
|
5035
5180
|
// 1st method: Via Scene SDK
|
|
5036
5181
|
if (this.sdk?.Scene?.addStyle) {
|
|
@@ -8046,11 +8191,11 @@ class ModalSwitchVisitComponent {
|
|
|
8046
8191
|
});
|
|
8047
8192
|
}
|
|
8048
8193
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ModalSwitchVisitComponent, deps: [{ token: i1$2.NgbActiveModal }, { token: i1$1.Router }, { token: ViewerService }], target: i0.ɵɵFactoryTarget.Component });
|
|
8049
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ModalSwitchVisitComponent, selector: "lib-modal-switch-visit", inputs: { content: "content", model3D: "model3D", spaceID: "spaceID", dataToMove: "dataToMove" }, ngImport: i0, template: "<div class=\"modal-container\">\n <p>{{content}}</p>\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"switchVisit()\">{{'Yes, switch visit' | translate }}</button>\n <button class=\"btn btn-outline-primary rounded-pill\"(click)=\"activeModal.close()\">{{'No, stay here' | translate }}</button>\n</div>\n", styles: [".modal-container{margin:10px}button{margin-right:8px}\n"], dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
8194
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ModalSwitchVisitComponent, selector: "lib-modal-switch-visit", inputs: { content: "content", model3D: "model3D", spaceID: "spaceID", dataToMove: "dataToMove" }, ngImport: i0, template: "<div class=\"modal-container\">\r\n <p>{{content}}</p>\r\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"switchVisit()\">{{'Yes, switch visit' | translate }}</button>\r\n <button class=\"btn btn-outline-primary rounded-pill\"(click)=\"activeModal.close()\">{{'No, stay here' | translate }}</button>\r\n</div>\r\n", styles: [".modal-container{margin:10px}button{margin-right:8px}\n"], dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
8050
8195
|
}
|
|
8051
8196
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ModalSwitchVisitComponent, decorators: [{
|
|
8052
8197
|
type: Component,
|
|
8053
|
-
args: [{ selector: 'lib-modal-switch-visit', template: "<div class=\"modal-container\">\n <p>{{content}}</p>\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"switchVisit()\">{{'Yes, switch visit' | translate }}</button>\n <button class=\"btn btn-outline-primary rounded-pill\"(click)=\"activeModal.close()\">{{'No, stay here' | translate }}</button>\n</div>\n", styles: [".modal-container{margin:10px}button{margin-right:8px}\n"] }]
|
|
8198
|
+
args: [{ selector: 'lib-modal-switch-visit', template: "<div class=\"modal-container\">\r\n <p>{{content}}</p>\r\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"switchVisit()\">{{'Yes, switch visit' | translate }}</button>\r\n <button class=\"btn btn-outline-primary rounded-pill\"(click)=\"activeModal.close()\">{{'No, stay here' | translate }}</button>\r\n</div>\r\n", styles: [".modal-container{margin:10px}button{margin-right:8px}\n"] }]
|
|
8054
8199
|
}], ctorParameters: () => [{ type: i1$2.NgbActiveModal }, { type: i1$1.Router }, { type: ViewerService }], propDecorators: { content: [{
|
|
8055
8200
|
type: Input
|
|
8056
8201
|
}], model3D: [{
|
|
@@ -8587,14 +8732,18 @@ class ZoneService {
|
|
|
8587
8732
|
async getZonesBySpace(spaceID) {
|
|
8588
8733
|
const list = [];
|
|
8589
8734
|
if (this.API.__proto__.hasOwnProperty('ZonesBySpace')) {
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8735
|
+
// Paginated: without a nextToken loop, only the first page (100 zones) was returned and
|
|
8736
|
+
// the sweeps of the other zones silently disappeared.
|
|
8737
|
+
let nextToken = null;
|
|
8738
|
+
do {
|
|
8739
|
+
const zones = await this.API.__proto__.ZonesBySpace(spaceID, null, null, 1000, nextToken);
|
|
8740
|
+
for (const zone of zones?.items || []) {
|
|
8593
8741
|
const zoneObject = { ...zone };
|
|
8594
8742
|
zoneObject.virtual = this.zoneIsVirtual(zone);
|
|
8595
8743
|
list.push(zoneObject);
|
|
8596
8744
|
}
|
|
8597
|
-
|
|
8745
|
+
nextToken = zones?.nextToken ?? null;
|
|
8746
|
+
} while (nextToken);
|
|
8598
8747
|
return list;
|
|
8599
8748
|
}
|
|
8600
8749
|
else {
|
|
@@ -13064,11 +13213,11 @@ class SearchBarComponent {
|
|
|
13064
13213
|
this.searchEvent.emit(results);
|
|
13065
13214
|
}
|
|
13066
13215
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SearchBarComponent, deps: [{ token: SearchService }], target: i0.ɵɵFactoryTarget.Component });
|
|
13067
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SearchBarComponent, selector: "lib-search-bar", inputs: { searchable: "searchable", objectType: "objectType" }, outputs: { searchEvent: "searchEvent" }, ngImport: i0, template: "<div class=\"col-md-8 searchbar\">\n <div class=\"row depend\">\n <div class=\"col-md-5\">\n <input id=\"searchbar\" type=\"text\" class=\"form-control\" placeholder=\"keyword\" />\n </div>\n <div class=\"col-md-5\">\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"onSubmit()\">{{ 'Search' |\n translate}}</button>\n </div>\n </div>\n</div>", styles: [".searchbar{margin-bottom:10px}\n"], dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
13216
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SearchBarComponent, selector: "lib-search-bar", inputs: { searchable: "searchable", objectType: "objectType" }, outputs: { searchEvent: "searchEvent" }, ngImport: i0, template: "<div class=\"col-md-8 searchbar\">\r\n <div class=\"row depend\">\r\n <div class=\"col-md-5\">\r\n <input id=\"searchbar\" type=\"text\" class=\"form-control\" placeholder=\"keyword\" />\r\n </div>\r\n <div class=\"col-md-5\">\r\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"onSubmit()\">{{ 'Search' |\r\n translate}}</button>\r\n </div>\r\n </div>\r\n</div>", styles: [".searchbar{margin-bottom:10px}\n"], dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
13068
13217
|
}
|
|
13069
13218
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SearchBarComponent, decorators: [{
|
|
13070
13219
|
type: Component,
|
|
13071
|
-
args: [{ selector: 'lib-search-bar', template: "<div class=\"col-md-8 searchbar\">\n <div class=\"row depend\">\n <div class=\"col-md-5\">\n <input id=\"searchbar\" type=\"text\" class=\"form-control\" placeholder=\"keyword\" />\n </div>\n <div class=\"col-md-5\">\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"onSubmit()\">{{ 'Search' |\n translate}}</button>\n </div>\n </div>\n</div>", styles: [".searchbar{margin-bottom:10px}\n"] }]
|
|
13220
|
+
args: [{ selector: 'lib-search-bar', template: "<div class=\"col-md-8 searchbar\">\r\n <div class=\"row depend\">\r\n <div class=\"col-md-5\">\r\n <input id=\"searchbar\" type=\"text\" class=\"form-control\" placeholder=\"keyword\" />\r\n </div>\r\n <div class=\"col-md-5\">\r\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"onSubmit()\">{{ 'Search' |\r\n translate}}</button>\r\n </div>\r\n </div>\r\n</div>", styles: [".searchbar{margin-bottom:10px}\n"] }]
|
|
13072
13221
|
}], ctorParameters: () => [{ type: SearchService }], propDecorators: { searchable: [{
|
|
13073
13222
|
type: Input
|
|
13074
13223
|
}], objectType: [{
|
|
@@ -13516,11 +13665,11 @@ class LoaderComponent {
|
|
|
13516
13665
|
document.documentElement.style.setProperty('--color', this.color);
|
|
13517
13666
|
}
|
|
13518
13667
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13519
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LoaderComponent, selector: "lib-loader", inputs: { useLogo: "useLogo", color: "color" }, ngImport: i0, template: "<div class=\"sk-fading-circle\">\n <img *ngIf=\"useLogo\" src=\"../../../../assets/icons/smarterplan.svg\">\n <div class=\"sk-circle1 sk-circle\"></div>\n <div class=\"sk-circle2 sk-circle\"></div>\n <div class=\"sk-circle3 sk-circle\"></div>\n <div class=\"sk-circle4 sk-circle\"></div>\n <div class=\"sk-circle5 sk-circle\"></div>\n <div class=\"sk-circle6 sk-circle\"></div>\n <div class=\"sk-circle7 sk-circle\"></div>\n <div class=\"sk-circle8 sk-circle\"></div>\n <div class=\"sk-circle9 sk-circle\"></div>\n <div class=\"sk-circle10 sk-circle\"></div>\n <div class=\"sk-circle11 sk-circle\"></div>\n <div class=\"sk-circle12 sk-circle\"></div>\n</div>\n", styles: [".sk-fading-circle{width:88px;height:88px;position:relative}.sk-fading-circle img{width:2rem;position:absolute;left:calc(50% - 16px);top:calc(50% - 16px)}.sk-fading-circle .sk-circle{width:100%;height:100%;position:absolute;left:0;top:0}.sk-fading-circle .sk-circle:before{content:\"\";display:block;margin:0 auto;width:15%;height:15%;background-color:var(--color);border-radius:100%;-webkit-animation:sk-circleFadeDelay 1.2s infinite ease-in-out both;animation:sk-circleFadeDelay 1.2s infinite ease-in-out both}.sk-fading-circle .sk-circle2{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);transform:rotate(30deg)}.sk-fading-circle .sk-circle3{-webkit-transform:rotate(60deg);-ms-transform:rotate(60deg);transform:rotate(60deg)}.sk-fading-circle .sk-circle4{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.sk-fading-circle .sk-circle5{-webkit-transform:rotate(120deg);-ms-transform:rotate(120deg);transform:rotate(120deg)}.sk-fading-circle .sk-circle6{-webkit-transform:rotate(150deg);-ms-transform:rotate(150deg);transform:rotate(150deg)}.sk-fading-circle .sk-circle7{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.sk-fading-circle .sk-circle8{-webkit-transform:rotate(210deg);-ms-transform:rotate(210deg);transform:rotate(210deg)}.sk-fading-circle .sk-circle9{-webkit-transform:rotate(240deg);-ms-transform:rotate(240deg);transform:rotate(240deg)}.sk-fading-circle .sk-circle10{-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.sk-fading-circle .sk-circle11{-webkit-transform:rotate(300deg);-ms-transform:rotate(300deg);transform:rotate(300deg)}.sk-fading-circle .sk-circle12{-webkit-transform:rotate(330deg);-ms-transform:rotate(330deg);transform:rotate(330deg)}.sk-fading-circle .sk-circle2:before{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.sk-fading-circle .sk-circle3:before{-webkit-animation-delay:-1s;animation-delay:-1s}.sk-fading-circle .sk-circle4:before{-webkit-animation-delay:-.9s;animation-delay:-.9s}.sk-fading-circle .sk-circle5:before{-webkit-animation-delay:-.8s;animation-delay:-.8s}.sk-fading-circle .sk-circle6:before{-webkit-animation-delay:-.7s;animation-delay:-.7s}.sk-fading-circle .sk-circle7:before{-webkit-animation-delay:-.6s;animation-delay:-.6s}.sk-fading-circle .sk-circle8:before{-webkit-animation-delay:-.5s;animation-delay:-.5s}.sk-fading-circle .sk-circle9:before{-webkit-animation-delay:-.4s;animation-delay:-.4s}.sk-fading-circle .sk-circle10:before{-webkit-animation-delay:-.3s;animation-delay:-.3s}.sk-fading-circle .sk-circle11:before{-webkit-animation-delay:-.2s;animation-delay:-.2s}.sk-fading-circle .sk-circle12:before{-webkit-animation-delay:-.1s;animation-delay:-.1s}@-webkit-keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}@keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}\n"], dependencies: [{ kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
13668
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LoaderComponent, selector: "lib-loader", inputs: { useLogo: "useLogo", color: "color" }, ngImport: i0, template: "<div class=\"sk-fading-circle\">\r\n <img *ngIf=\"useLogo\" src=\"../../../../assets/icons/smarterplan.svg\">\r\n <div class=\"sk-circle1 sk-circle\"></div>\r\n <div class=\"sk-circle2 sk-circle\"></div>\r\n <div class=\"sk-circle3 sk-circle\"></div>\r\n <div class=\"sk-circle4 sk-circle\"></div>\r\n <div class=\"sk-circle5 sk-circle\"></div>\r\n <div class=\"sk-circle6 sk-circle\"></div>\r\n <div class=\"sk-circle7 sk-circle\"></div>\r\n <div class=\"sk-circle8 sk-circle\"></div>\r\n <div class=\"sk-circle9 sk-circle\"></div>\r\n <div class=\"sk-circle10 sk-circle\"></div>\r\n <div class=\"sk-circle11 sk-circle\"></div>\r\n <div class=\"sk-circle12 sk-circle\"></div>\r\n</div>\r\n", styles: [".sk-fading-circle{width:88px;height:88px;position:relative}.sk-fading-circle img{width:2rem;position:absolute;left:calc(50% - 16px);top:calc(50% - 16px)}.sk-fading-circle .sk-circle{width:100%;height:100%;position:absolute;left:0;top:0}.sk-fading-circle .sk-circle:before{content:\"\";display:block;margin:0 auto;width:15%;height:15%;background-color:var(--color);border-radius:100%;-webkit-animation:sk-circleFadeDelay 1.2s infinite ease-in-out both;animation:sk-circleFadeDelay 1.2s infinite ease-in-out both}.sk-fading-circle .sk-circle2{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);transform:rotate(30deg)}.sk-fading-circle .sk-circle3{-webkit-transform:rotate(60deg);-ms-transform:rotate(60deg);transform:rotate(60deg)}.sk-fading-circle .sk-circle4{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.sk-fading-circle .sk-circle5{-webkit-transform:rotate(120deg);-ms-transform:rotate(120deg);transform:rotate(120deg)}.sk-fading-circle .sk-circle6{-webkit-transform:rotate(150deg);-ms-transform:rotate(150deg);transform:rotate(150deg)}.sk-fading-circle .sk-circle7{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.sk-fading-circle .sk-circle8{-webkit-transform:rotate(210deg);-ms-transform:rotate(210deg);transform:rotate(210deg)}.sk-fading-circle .sk-circle9{-webkit-transform:rotate(240deg);-ms-transform:rotate(240deg);transform:rotate(240deg)}.sk-fading-circle .sk-circle10{-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.sk-fading-circle .sk-circle11{-webkit-transform:rotate(300deg);-ms-transform:rotate(300deg);transform:rotate(300deg)}.sk-fading-circle .sk-circle12{-webkit-transform:rotate(330deg);-ms-transform:rotate(330deg);transform:rotate(330deg)}.sk-fading-circle .sk-circle2:before{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.sk-fading-circle .sk-circle3:before{-webkit-animation-delay:-1s;animation-delay:-1s}.sk-fading-circle .sk-circle4:before{-webkit-animation-delay:-.9s;animation-delay:-.9s}.sk-fading-circle .sk-circle5:before{-webkit-animation-delay:-.8s;animation-delay:-.8s}.sk-fading-circle .sk-circle6:before{-webkit-animation-delay:-.7s;animation-delay:-.7s}.sk-fading-circle .sk-circle7:before{-webkit-animation-delay:-.6s;animation-delay:-.6s}.sk-fading-circle .sk-circle8:before{-webkit-animation-delay:-.5s;animation-delay:-.5s}.sk-fading-circle .sk-circle9:before{-webkit-animation-delay:-.4s;animation-delay:-.4s}.sk-fading-circle .sk-circle10:before{-webkit-animation-delay:-.3s;animation-delay:-.3s}.sk-fading-circle .sk-circle11:before{-webkit-animation-delay:-.2s;animation-delay:-.2s}.sk-fading-circle .sk-circle12:before{-webkit-animation-delay:-.1s;animation-delay:-.1s}@-webkit-keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}@keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}\n"], dependencies: [{ kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
13520
13669
|
}
|
|
13521
13670
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LoaderComponent, decorators: [{
|
|
13522
13671
|
type: Component,
|
|
13523
|
-
args: [{ selector: 'lib-loader', template: "<div class=\"sk-fading-circle\">\n <img *ngIf=\"useLogo\" src=\"../../../../assets/icons/smarterplan.svg\">\n <div class=\"sk-circle1 sk-circle\"></div>\n <div class=\"sk-circle2 sk-circle\"></div>\n <div class=\"sk-circle3 sk-circle\"></div>\n <div class=\"sk-circle4 sk-circle\"></div>\n <div class=\"sk-circle5 sk-circle\"></div>\n <div class=\"sk-circle6 sk-circle\"></div>\n <div class=\"sk-circle7 sk-circle\"></div>\n <div class=\"sk-circle8 sk-circle\"></div>\n <div class=\"sk-circle9 sk-circle\"></div>\n <div class=\"sk-circle10 sk-circle\"></div>\n <div class=\"sk-circle11 sk-circle\"></div>\n <div class=\"sk-circle12 sk-circle\"></div>\n</div>\n", styles: [".sk-fading-circle{width:88px;height:88px;position:relative}.sk-fading-circle img{width:2rem;position:absolute;left:calc(50% - 16px);top:calc(50% - 16px)}.sk-fading-circle .sk-circle{width:100%;height:100%;position:absolute;left:0;top:0}.sk-fading-circle .sk-circle:before{content:\"\";display:block;margin:0 auto;width:15%;height:15%;background-color:var(--color);border-radius:100%;-webkit-animation:sk-circleFadeDelay 1.2s infinite ease-in-out both;animation:sk-circleFadeDelay 1.2s infinite ease-in-out both}.sk-fading-circle .sk-circle2{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);transform:rotate(30deg)}.sk-fading-circle .sk-circle3{-webkit-transform:rotate(60deg);-ms-transform:rotate(60deg);transform:rotate(60deg)}.sk-fading-circle .sk-circle4{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.sk-fading-circle .sk-circle5{-webkit-transform:rotate(120deg);-ms-transform:rotate(120deg);transform:rotate(120deg)}.sk-fading-circle .sk-circle6{-webkit-transform:rotate(150deg);-ms-transform:rotate(150deg);transform:rotate(150deg)}.sk-fading-circle .sk-circle7{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.sk-fading-circle .sk-circle8{-webkit-transform:rotate(210deg);-ms-transform:rotate(210deg);transform:rotate(210deg)}.sk-fading-circle .sk-circle9{-webkit-transform:rotate(240deg);-ms-transform:rotate(240deg);transform:rotate(240deg)}.sk-fading-circle .sk-circle10{-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.sk-fading-circle .sk-circle11{-webkit-transform:rotate(300deg);-ms-transform:rotate(300deg);transform:rotate(300deg)}.sk-fading-circle .sk-circle12{-webkit-transform:rotate(330deg);-ms-transform:rotate(330deg);transform:rotate(330deg)}.sk-fading-circle .sk-circle2:before{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.sk-fading-circle .sk-circle3:before{-webkit-animation-delay:-1s;animation-delay:-1s}.sk-fading-circle .sk-circle4:before{-webkit-animation-delay:-.9s;animation-delay:-.9s}.sk-fading-circle .sk-circle5:before{-webkit-animation-delay:-.8s;animation-delay:-.8s}.sk-fading-circle .sk-circle6:before{-webkit-animation-delay:-.7s;animation-delay:-.7s}.sk-fading-circle .sk-circle7:before{-webkit-animation-delay:-.6s;animation-delay:-.6s}.sk-fading-circle .sk-circle8:before{-webkit-animation-delay:-.5s;animation-delay:-.5s}.sk-fading-circle .sk-circle9:before{-webkit-animation-delay:-.4s;animation-delay:-.4s}.sk-fading-circle .sk-circle10:before{-webkit-animation-delay:-.3s;animation-delay:-.3s}.sk-fading-circle .sk-circle11:before{-webkit-animation-delay:-.2s;animation-delay:-.2s}.sk-fading-circle .sk-circle12:before{-webkit-animation-delay:-.1s;animation-delay:-.1s}@-webkit-keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}@keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}\n"] }]
|
|
13672
|
+
args: [{ selector: 'lib-loader', template: "<div class=\"sk-fading-circle\">\r\n <img *ngIf=\"useLogo\" src=\"../../../../assets/icons/smarterplan.svg\">\r\n <div class=\"sk-circle1 sk-circle\"></div>\r\n <div class=\"sk-circle2 sk-circle\"></div>\r\n <div class=\"sk-circle3 sk-circle\"></div>\r\n <div class=\"sk-circle4 sk-circle\"></div>\r\n <div class=\"sk-circle5 sk-circle\"></div>\r\n <div class=\"sk-circle6 sk-circle\"></div>\r\n <div class=\"sk-circle7 sk-circle\"></div>\r\n <div class=\"sk-circle8 sk-circle\"></div>\r\n <div class=\"sk-circle9 sk-circle\"></div>\r\n <div class=\"sk-circle10 sk-circle\"></div>\r\n <div class=\"sk-circle11 sk-circle\"></div>\r\n <div class=\"sk-circle12 sk-circle\"></div>\r\n</div>\r\n", styles: [".sk-fading-circle{width:88px;height:88px;position:relative}.sk-fading-circle img{width:2rem;position:absolute;left:calc(50% - 16px);top:calc(50% - 16px)}.sk-fading-circle .sk-circle{width:100%;height:100%;position:absolute;left:0;top:0}.sk-fading-circle .sk-circle:before{content:\"\";display:block;margin:0 auto;width:15%;height:15%;background-color:var(--color);border-radius:100%;-webkit-animation:sk-circleFadeDelay 1.2s infinite ease-in-out both;animation:sk-circleFadeDelay 1.2s infinite ease-in-out both}.sk-fading-circle .sk-circle2{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);transform:rotate(30deg)}.sk-fading-circle .sk-circle3{-webkit-transform:rotate(60deg);-ms-transform:rotate(60deg);transform:rotate(60deg)}.sk-fading-circle .sk-circle4{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.sk-fading-circle .sk-circle5{-webkit-transform:rotate(120deg);-ms-transform:rotate(120deg);transform:rotate(120deg)}.sk-fading-circle .sk-circle6{-webkit-transform:rotate(150deg);-ms-transform:rotate(150deg);transform:rotate(150deg)}.sk-fading-circle .sk-circle7{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.sk-fading-circle .sk-circle8{-webkit-transform:rotate(210deg);-ms-transform:rotate(210deg);transform:rotate(210deg)}.sk-fading-circle .sk-circle9{-webkit-transform:rotate(240deg);-ms-transform:rotate(240deg);transform:rotate(240deg)}.sk-fading-circle .sk-circle10{-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.sk-fading-circle .sk-circle11{-webkit-transform:rotate(300deg);-ms-transform:rotate(300deg);transform:rotate(300deg)}.sk-fading-circle .sk-circle12{-webkit-transform:rotate(330deg);-ms-transform:rotate(330deg);transform:rotate(330deg)}.sk-fading-circle .sk-circle2:before{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.sk-fading-circle .sk-circle3:before{-webkit-animation-delay:-1s;animation-delay:-1s}.sk-fading-circle .sk-circle4:before{-webkit-animation-delay:-.9s;animation-delay:-.9s}.sk-fading-circle .sk-circle5:before{-webkit-animation-delay:-.8s;animation-delay:-.8s}.sk-fading-circle .sk-circle6:before{-webkit-animation-delay:-.7s;animation-delay:-.7s}.sk-fading-circle .sk-circle7:before{-webkit-animation-delay:-.6s;animation-delay:-.6s}.sk-fading-circle .sk-circle8:before{-webkit-animation-delay:-.5s;animation-delay:-.5s}.sk-fading-circle .sk-circle9:before{-webkit-animation-delay:-.4s;animation-delay:-.4s}.sk-fading-circle .sk-circle10:before{-webkit-animation-delay:-.3s;animation-delay:-.3s}.sk-fading-circle .sk-circle11:before{-webkit-animation-delay:-.2s;animation-delay:-.2s}.sk-fading-circle .sk-circle12:before{-webkit-animation-delay:-.1s;animation-delay:-.1s}@-webkit-keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}@keyframes sk-circleFadeDelay{0%,39%,to{opacity:0}40%{opacity:1}}\n"] }]
|
|
13524
13673
|
}], ctorParameters: () => [], propDecorators: { useLogo: [{
|
|
13525
13674
|
type: Input
|
|
13526
13675
|
}], color: [{
|
|
@@ -13578,11 +13727,11 @@ class SupportModalComponent {
|
|
|
13578
13727
|
}
|
|
13579
13728
|
}
|
|
13580
13729
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SupportModalComponent, deps: [{ token: SupportService }, { token: i1$2.NgbActiveModal }, { token: i3.UntypedFormBuilder }, { token: BaseUserService }, { token: ValidatorsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
13581
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SupportModalComponent, selector: "app-support-modal", ngImport: i0, template: "<div class=\"modal-header\">\n <h5 class=\"modal-title\" translate=\"Help\"></h5>\n</div>\n<div class=\"modal-body\">\n <div class=\"support-loader-container\">\n <lib-loader *ngIf=\"loading\"></lib-loader>\n </div>\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"supportForm\" style=\"margin-top:1rem;\" *ngIf=\"!loading && status==='new'\">\n <div>\n <label>{{'Title' | translate}} *</label>\n <div>\n <input type=\"text\" class=\"form-control\" formControlName=\"title\" data-testid=\"new-support-title\"\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['title'])}\"\n maxlength=\"255\">\n </div>\n <div class=\"invalid-feedback\">\n <span data-testid=\"new-support-title-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['title'])\"\n *ngIf=\" validatorsService.isControlError(supportForm.controls['title'])\"></span>\n </div>\n </div>\n <div *ngIf=\"!currentUser\">\n <label>{{'Email' | translate}} *</label>\n <div>\n <input type=\"email\" class=\"form-control\" formControlName=\"email\" data-testid=\"new-support-email\"\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['email'])}\"\n maxlength=\"255\">\n </div>\n <div class=\"invalid-feedback\">\n <span data-testid=\"new-support-email-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['email'])\"\n *ngIf=\" validatorsService.isControlError(supportForm.controls['email'])\"></span>\n </div>\n </div>\n <div>\n <label>{{'Description' | translate}} *</label>\n <div>\n <textarea formControlName=\"description\" class=\"form-control\"\n data-testid=\"new-support-description\"\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['description'])}\"></textarea>\n </div>\n <div class=\"invalid-feedback\" >\n <span data-testid=\"new-support-description-invalid\" [translate]=\" validatorsService.getError(supportForm.controls['description'])\"\n *ngIf=\"validatorsService.isControlError(supportForm.controls['description'])\"></span>\n </div>\n </div>\n </form>\n\n <div *ngIf=\"status ==='send'\" translate=\"Your request has been registered\" data-testid=\"new-support-send-info\">\n </div>\n <div *ngIf=\"status ==='error'\" translate=\"An error has occurred, please renew your request\"\n data-testid=\"new-support-error-info\">\n\n </div>\n</div>\n<div class=\"modal-footer\">\n <button type=\"button\" class=\"btn rounded-pill btn-museum\" data-dismiss=\"modal\" translate=\"Close\" (click)=\"onClose()\"\n data-testid=\"new-support-close-btn\"></button>\n <button *ngIf=\"!loading && status==='new'\" type=\"button\" class=\"btn rounded-pill btn-museum\" translate=\"Submit\"\n (click)=\"onSubmit()\" [disabled]=\"!supportForm.valid\" data-testid=\"new-support-submit-btn\"></button>\n</div>", styles: [".support-loader-container{width:88px;margin:auto}.invalid-feedback{height:16px}\n"], dependencies: [{ kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i11.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: LoaderComponent, selector: "lib-loader", inputs: ["useLogo", "color"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
13730
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SupportModalComponent, selector: "app-support-modal", ngImport: i0, template: "<div class=\"modal-header\">\r\n <h5 class=\"modal-title\" translate=\"Help\"></h5>\r\n</div>\r\n<div class=\"modal-body\">\r\n <div class=\"support-loader-container\">\r\n <lib-loader *ngIf=\"loading\"></lib-loader>\r\n </div>\r\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"supportForm\" style=\"margin-top:1rem;\" *ngIf=\"!loading && status==='new'\">\r\n <div>\r\n <label>{{'Title' | translate}} *</label>\r\n <div>\r\n <input type=\"text\" class=\"form-control\" formControlName=\"title\" data-testid=\"new-support-title\"\r\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['title'])}\"\r\n maxlength=\"255\">\r\n </div>\r\n <div class=\"invalid-feedback\">\r\n <span data-testid=\"new-support-title-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['title'])\"\r\n *ngIf=\" validatorsService.isControlError(supportForm.controls['title'])\"></span>\r\n </div>\r\n </div>\r\n <div *ngIf=\"!currentUser\">\r\n <label>{{'Email' | translate}} *</label>\r\n <div>\r\n <input type=\"email\" class=\"form-control\" formControlName=\"email\" data-testid=\"new-support-email\"\r\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['email'])}\"\r\n maxlength=\"255\">\r\n </div>\r\n <div class=\"invalid-feedback\">\r\n <span data-testid=\"new-support-email-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['email'])\"\r\n *ngIf=\" validatorsService.isControlError(supportForm.controls['email'])\"></span>\r\n </div>\r\n </div>\r\n <div>\r\n <label>{{'Description' | translate}} *</label>\r\n <div>\r\n <textarea formControlName=\"description\" class=\"form-control\"\r\n data-testid=\"new-support-description\"\r\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['description'])}\"></textarea>\r\n </div>\r\n <div class=\"invalid-feedback\" >\r\n <span data-testid=\"new-support-description-invalid\" [translate]=\" validatorsService.getError(supportForm.controls['description'])\"\r\n *ngIf=\"validatorsService.isControlError(supportForm.controls['description'])\"></span>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div *ngIf=\"status ==='send'\" translate=\"Your request has been registered\" data-testid=\"new-support-send-info\">\r\n </div>\r\n <div *ngIf=\"status ==='error'\" translate=\"An error has occurred, please renew your request\"\r\n data-testid=\"new-support-error-info\">\r\n\r\n </div>\r\n</div>\r\n<div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn rounded-pill btn-museum\" data-dismiss=\"modal\" translate=\"Close\" (click)=\"onClose()\"\r\n data-testid=\"new-support-close-btn\"></button>\r\n <button *ngIf=\"!loading && status==='new'\" type=\"button\" class=\"btn rounded-pill btn-museum\" translate=\"Submit\"\r\n (click)=\"onSubmit()\" [disabled]=\"!supportForm.valid\" data-testid=\"new-support-submit-btn\"></button>\r\n</div>", styles: [".support-loader-container{width:88px;margin:auto}.invalid-feedback{height:16px}\n"], dependencies: [{ kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i11.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: LoaderComponent, selector: "lib-loader", inputs: ["useLogo", "color"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
13582
13731
|
}
|
|
13583
13732
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SupportModalComponent, decorators: [{
|
|
13584
13733
|
type: Component,
|
|
13585
|
-
args: [{ selector: 'app-support-modal', template: "<div class=\"modal-header\">\n <h5 class=\"modal-title\" translate=\"Help\"></h5>\n</div>\n<div class=\"modal-body\">\n <div class=\"support-loader-container\">\n <lib-loader *ngIf=\"loading\"></lib-loader>\n </div>\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"supportForm\" style=\"margin-top:1rem;\" *ngIf=\"!loading && status==='new'\">\n <div>\n <label>{{'Title' | translate}} *</label>\n <div>\n <input type=\"text\" class=\"form-control\" formControlName=\"title\" data-testid=\"new-support-title\"\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['title'])}\"\n maxlength=\"255\">\n </div>\n <div class=\"invalid-feedback\">\n <span data-testid=\"new-support-title-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['title'])\"\n *ngIf=\" validatorsService.isControlError(supportForm.controls['title'])\"></span>\n </div>\n </div>\n <div *ngIf=\"!currentUser\">\n <label>{{'Email' | translate}} *</label>\n <div>\n <input type=\"email\" class=\"form-control\" formControlName=\"email\" data-testid=\"new-support-email\"\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['email'])}\"\n maxlength=\"255\">\n </div>\n <div class=\"invalid-feedback\">\n <span data-testid=\"new-support-email-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['email'])\"\n *ngIf=\" validatorsService.isControlError(supportForm.controls['email'])\"></span>\n </div>\n </div>\n <div>\n <label>{{'Description' | translate}} *</label>\n <div>\n <textarea formControlName=\"description\" class=\"form-control\"\n data-testid=\"new-support-description\"\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['description'])}\"></textarea>\n </div>\n <div class=\"invalid-feedback\" >\n <span data-testid=\"new-support-description-invalid\" [translate]=\" validatorsService.getError(supportForm.controls['description'])\"\n *ngIf=\"validatorsService.isControlError(supportForm.controls['description'])\"></span>\n </div>\n </div>\n </form>\n\n <div *ngIf=\"status ==='send'\" translate=\"Your request has been registered\" data-testid=\"new-support-send-info\">\n </div>\n <div *ngIf=\"status ==='error'\" translate=\"An error has occurred, please renew your request\"\n data-testid=\"new-support-error-info\">\n\n </div>\n</div>\n<div class=\"modal-footer\">\n <button type=\"button\" class=\"btn rounded-pill btn-museum\" data-dismiss=\"modal\" translate=\"Close\" (click)=\"onClose()\"\n data-testid=\"new-support-close-btn\"></button>\n <button *ngIf=\"!loading && status==='new'\" type=\"button\" class=\"btn rounded-pill btn-museum\" translate=\"Submit\"\n (click)=\"onSubmit()\" [disabled]=\"!supportForm.valid\" data-testid=\"new-support-submit-btn\"></button>\n</div>", styles: [".support-loader-container{width:88px;margin:auto}.invalid-feedback{height:16px}\n"] }]
|
|
13734
|
+
args: [{ selector: 'app-support-modal', template: "<div class=\"modal-header\">\r\n <h5 class=\"modal-title\" translate=\"Help\"></h5>\r\n</div>\r\n<div class=\"modal-body\">\r\n <div class=\"support-loader-container\">\r\n <lib-loader *ngIf=\"loading\"></lib-loader>\r\n </div>\r\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"supportForm\" style=\"margin-top:1rem;\" *ngIf=\"!loading && status==='new'\">\r\n <div>\r\n <label>{{'Title' | translate}} *</label>\r\n <div>\r\n <input type=\"text\" class=\"form-control\" formControlName=\"title\" data-testid=\"new-support-title\"\r\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['title'])}\"\r\n maxlength=\"255\">\r\n </div>\r\n <div class=\"invalid-feedback\">\r\n <span data-testid=\"new-support-title-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['title'])\"\r\n *ngIf=\" validatorsService.isControlError(supportForm.controls['title'])\"></span>\r\n </div>\r\n </div>\r\n <div *ngIf=\"!currentUser\">\r\n <label>{{'Email' | translate}} *</label>\r\n <div>\r\n <input type=\"email\" class=\"form-control\" formControlName=\"email\" data-testid=\"new-support-email\"\r\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['email'])}\"\r\n maxlength=\"255\">\r\n </div>\r\n <div class=\"invalid-feedback\">\r\n <span data-testid=\"new-support-email-invalid\" [translate]=\"validatorsService.getError(supportForm.controls['email'])\"\r\n *ngIf=\" validatorsService.isControlError(supportForm.controls['email'])\"></span>\r\n </div>\r\n </div>\r\n <div>\r\n <label>{{'Description' | translate}} *</label>\r\n <div>\r\n <textarea formControlName=\"description\" class=\"form-control\"\r\n data-testid=\"new-support-description\"\r\n [ngClass]=\"{'is-invalid' : validatorsService.isControlError(supportForm.controls['description'])}\"></textarea>\r\n </div>\r\n <div class=\"invalid-feedback\" >\r\n <span data-testid=\"new-support-description-invalid\" [translate]=\" validatorsService.getError(supportForm.controls['description'])\"\r\n *ngIf=\"validatorsService.isControlError(supportForm.controls['description'])\"></span>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div *ngIf=\"status ==='send'\" translate=\"Your request has been registered\" data-testid=\"new-support-send-info\">\r\n </div>\r\n <div *ngIf=\"status ==='error'\" translate=\"An error has occurred, please renew your request\"\r\n data-testid=\"new-support-error-info\">\r\n\r\n </div>\r\n</div>\r\n<div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn rounded-pill btn-museum\" data-dismiss=\"modal\" translate=\"Close\" (click)=\"onClose()\"\r\n data-testid=\"new-support-close-btn\"></button>\r\n <button *ngIf=\"!loading && status==='new'\" type=\"button\" class=\"btn rounded-pill btn-museum\" translate=\"Submit\"\r\n (click)=\"onSubmit()\" [disabled]=\"!supportForm.valid\" data-testid=\"new-support-submit-btn\"></button>\r\n</div>", styles: [".support-loader-container{width:88px;margin:auto}.invalid-feedback{height:16px}\n"] }]
|
|
13586
13735
|
}], ctorParameters: () => [{ type: SupportService }, { type: i1$2.NgbActiveModal }, { type: i3.UntypedFormBuilder }, { type: BaseUserService }, { type: ValidatorsService }] });
|
|
13587
13736
|
|
|
13588
13737
|
class LocaleService {
|
|
@@ -14993,11 +15142,11 @@ class NavigationBarComponent {
|
|
|
14993
15142
|
this.baseVisibilityService.isChangePositionVisible.next(false);
|
|
14994
15143
|
}
|
|
14995
15144
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NavigationBarComponent, deps: [{ token: 'currentAwsKinesisAnalyticsService' }, { token: i1$1.Router }, { token: SpaceService }, { token: BaseUserService }, { token: ZoneService }, { token: VisitService }, { token: ViewerService }, { token: NavigatorService }, { token: ZoneChangeService }, { token: BaseVisibilityService }], target: i0.ɵɵFactoryTarget.Component });
|
|
14996
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NavigationBarComponent, selector: "lib-navigation-bar", viewQueries: [{ propertyName: "navbarSelectMenu", first: true, predicate: ["navbarSelectMenu"], descendants: true }], ngImport: i0, template: "<nav class=\"navbar navbar-expand-md navbar-dark navbar-inverse second-nav\">\n <div class=\"d-flex w-100\">\n <div #navbarSelectMenu class=\"w-100\" id=\"nav-item-container-blue\">\n <div class=\"d-flex flex-column flex-md-row p-1 mt-2\">\n <select class=\"form-control flex-fill flex-lg-fill-unset location select-menu\"\n [(ngModel)]=\"selectedLocation\" (ngModelChange)=\"onLocationClick()\">\n <option [ngValue]=\"null\" selected>{{ 'Location' | translate }}</option>\n <option *ngFor=\"let loc of locations; index as index\" [ngValue]=\"loc\"> {{ loc.name }}</option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" (change)=\"onVisitClick($event)\"\n *ngIf=\"visitsPerSpace && visitsPerSpace.length > 1\">\n <option value=\"default\" selected disabled hidden>{{'Visit' | translate}}</option>\n <option *ngFor=\"let visit of visitsPerSpace; index as index\" value=\"{{index}}\">{{ visit.name}}\n </option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset floor select-menu\" [(ngModel)]=\"selectedFloor\"\n (ngModelChange)=\"onFloorClick()\">\n <option [ngValue]=\"null\" selected>{{'Floor' | translate}}</option>\n <option *ngFor=\"let floor of floorsPerSpace\" [ngValue]=\"floor\">{{ floor.name}}</option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu zone\" [(ngModel)]=\"selectedZone\"\n (ngModelChange)=\"onZoneClick()\">\n <option [ngValue]=\"null\" selected>{{'Zone' | translate}}</option>\n <option *ngFor=\"let zone of zonesPerFloor\" [ngValue]=\"zone\"><span\n *ngIf=\"zone.code_ref\">{{zone.code_ref}}_</span>{{zone.name}}</option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" [(ngModel)]=\"selectedChildZone\"\n *ngIf=\"childrenZones && childrenZones.length>0\" (ngModelChange)=\"onChildZoneClick()\">\n <option [ngValue]=\"null\" selected disabled>{{'Zone' | translate}}</option>\n <option *ngFor=\"let zone of childrenZones\" [ngValue]=\"zone\">{{ zone.name}}</option>\n </select>\n <button (click)=\"goTo()\"\n class=\"btn btn-outline-primary rounded-pill mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d d-none d-lg-block\"\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\n </button>\n </div>\n <div class=\"row align-items-center justify-content-center ml-0 p-1\" *ngIf=\"showLocation()\">\n <p class=\"fw-bold lh-base align-middle text-center\">\n {{ showLocation() }}\n </p>\n </div>\n <div class=\"row align-items-center justify-content-center ml-0 p-1 d-block d-lg-none\">\n <button (click)=\"goTo()\"\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d\"\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\n </button>\n </div>\n </div>\n </div>\n</nav>", styles: [":host{position:sticky;top:0;height:123px}.navbar{z-index:200;padding:.4rem 1rem}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0}@media (min-width: 992px){.flex-lg-fill-unset{flex:unset!important}}.form-control{width:100%;min-width:80px;max-width:18%}.location{width:auto;max-width:35%}.floor,.zone{width:auto;max-width:30%}button{color:#fff;padding:5px 10px;font-size:1.1em}.navbar-toggler{margin-right:1em}.select-menu{max-width:inherit}.btn-3d .icon-go-to-3d{width:30px;height:30px;background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0A<style type=\"text/css\">%0A%09.st0{fill:%23565656;}%0A<\\/style>%0A<g>%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0A%09%09/>%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0A</g>%0A</svg>%0A');border:none;vertical-align:middle;fill:var(--smarterplan-primary)}.btn-3d:hover:enabled .icon-go-to-3d{background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0A<style type=\"text/css\">%0A%09.st0{fill:%23FFFFFF;}%0A<\\/style>%0A<g>%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0A%09%09/>%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0A</g>%0A</svg>%0A')}.btn-3d[disabled]:hover .icon-go-to-3d{fill:var(--smarterplan-primary)}.outer_circle{background-color:#ebebeb;border-radius:50%;width:32px;height:32px;padding:1px}@media (max-width: 767px){.navbar{padding:.2rem .5rem}.form-control,.location,.floor,.zone{max-width:100%;margin-bottom:15px}input,select{margin-right:0;margin-bottom:15px}}\n"], dependencies: [{ kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
15145
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NavigationBarComponent, selector: "lib-navigation-bar", viewQueries: [{ propertyName: "navbarSelectMenu", first: true, predicate: ["navbarSelectMenu"], descendants: true }], ngImport: i0, template: "<nav class=\"navbar navbar-expand-md navbar-dark navbar-inverse second-nav\">\r\n <div class=\"d-flex w-100\">\r\n <div #navbarSelectMenu class=\"w-100\" id=\"nav-item-container-blue\">\r\n <div class=\"d-flex flex-column flex-md-row p-1 mt-2\">\r\n <select class=\"form-control flex-fill flex-lg-fill-unset location select-menu\"\r\n [(ngModel)]=\"selectedLocation\" (ngModelChange)=\"onLocationClick()\">\r\n <option [ngValue]=\"null\" selected>{{ 'Location' | translate }}</option>\r\n <option *ngFor=\"let loc of locations; index as index\" [ngValue]=\"loc\"> {{ loc.name }}</option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" (change)=\"onVisitClick($event)\"\r\n *ngIf=\"visitsPerSpace && visitsPerSpace.length > 1\">\r\n <option value=\"default\" selected disabled hidden>{{'Visit' | translate}}</option>\r\n <option *ngFor=\"let visit of visitsPerSpace; index as index\" value=\"{{index}}\">{{ visit.name}}\r\n </option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset floor select-menu\" [(ngModel)]=\"selectedFloor\"\r\n (ngModelChange)=\"onFloorClick()\">\r\n <option [ngValue]=\"null\" selected>{{'Floor' | translate}}</option>\r\n <option *ngFor=\"let floor of floorsPerSpace\" [ngValue]=\"floor\">{{ floor.name}}</option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu zone\" [(ngModel)]=\"selectedZone\"\r\n (ngModelChange)=\"onZoneClick()\">\r\n <option [ngValue]=\"null\" selected>{{'Zone' | translate}}</option>\r\n <option *ngFor=\"let zone of zonesPerFloor\" [ngValue]=\"zone\"><span\r\n *ngIf=\"zone.code_ref\">{{zone.code_ref}}_</span>{{zone.name}}</option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" [(ngModel)]=\"selectedChildZone\"\r\n *ngIf=\"childrenZones && childrenZones.length>0\" (ngModelChange)=\"onChildZoneClick()\">\r\n <option [ngValue]=\"null\" selected disabled>{{'Zone' | translate}}</option>\r\n <option *ngFor=\"let zone of childrenZones\" [ngValue]=\"zone\">{{ zone.name}}</option>\r\n </select>\r\n <button (click)=\"goTo()\"\r\n class=\"btn btn-outline-primary rounded-pill mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d d-none d-lg-block\"\r\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\r\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\r\n </button>\r\n </div>\r\n <div class=\"row align-items-center justify-content-center ml-0 p-1\" *ngIf=\"showLocation()\">\r\n <p class=\"fw-bold lh-base align-middle text-center\">\r\n {{ showLocation() }}\r\n </p>\r\n </div>\r\n <div class=\"row align-items-center justify-content-center ml-0 p-1 d-block d-lg-none\">\r\n <button (click)=\"goTo()\"\r\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d\"\r\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\r\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</nav>", styles: [":host{position:sticky;top:0;height:123px}.navbar{z-index:200;padding:.4rem 1rem}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0}@media (min-width: 992px){.flex-lg-fill-unset{flex:unset!important}}.form-control{width:100%;min-width:80px;max-width:18%}.location{width:auto;max-width:35%}.floor,.zone{width:auto;max-width:30%}button{color:#fff;padding:5px 10px;font-size:1.1em}.navbar-toggler{margin-right:1em}.select-menu{max-width:inherit}.btn-3d .icon-go-to-3d{width:30px;height:30px;background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0D%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0D%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0D%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0D%0A<style type=\"text/css\">%0D%0A%09.st0{fill:%23565656;}%0D%0A<\\/style>%0D%0A<g>%0D%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0D%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0D%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0D%0A%09%09/>%0D%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0D%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0D%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0D%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0D%0A</g>%0D%0A</svg>%0D%0A');border:none;vertical-align:middle;fill:var(--smarterplan-primary)}.btn-3d:hover:enabled .icon-go-to-3d{background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0D%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0D%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0D%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0D%0A<style type=\"text/css\">%0D%0A%09.st0{fill:%23FFFFFF;}%0D%0A<\\/style>%0D%0A<g>%0D%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0D%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0D%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0D%0A%09%09/>%0D%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0D%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0D%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0D%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0D%0A</g>%0D%0A</svg>%0D%0A')}.btn-3d[disabled]:hover .icon-go-to-3d{fill:var(--smarterplan-primary)}.outer_circle{background-color:#ebebeb;border-radius:50%;width:32px;height:32px;padding:1px}@media (max-width: 767px){.navbar{padding:.2rem .5rem}.form-control,.location,.floor,.zone{max-width:100%;margin-bottom:15px}input,select{margin-right:0;margin-bottom:15px}}\n"], dependencies: [{ kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
14997
15146
|
}
|
|
14998
15147
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NavigationBarComponent, decorators: [{
|
|
14999
15148
|
type: Component,
|
|
15000
|
-
args: [{ selector: 'lib-navigation-bar', template: "<nav class=\"navbar navbar-expand-md navbar-dark navbar-inverse second-nav\">\n <div class=\"d-flex w-100\">\n <div #navbarSelectMenu class=\"w-100\" id=\"nav-item-container-blue\">\n <div class=\"d-flex flex-column flex-md-row p-1 mt-2\">\n <select class=\"form-control flex-fill flex-lg-fill-unset location select-menu\"\n [(ngModel)]=\"selectedLocation\" (ngModelChange)=\"onLocationClick()\">\n <option [ngValue]=\"null\" selected>{{ 'Location' | translate }}</option>\n <option *ngFor=\"let loc of locations; index as index\" [ngValue]=\"loc\"> {{ loc.name }}</option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" (change)=\"onVisitClick($event)\"\n *ngIf=\"visitsPerSpace && visitsPerSpace.length > 1\">\n <option value=\"default\" selected disabled hidden>{{'Visit' | translate}}</option>\n <option *ngFor=\"let visit of visitsPerSpace; index as index\" value=\"{{index}}\">{{ visit.name}}\n </option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset floor select-menu\" [(ngModel)]=\"selectedFloor\"\n (ngModelChange)=\"onFloorClick()\">\n <option [ngValue]=\"null\" selected>{{'Floor' | translate}}</option>\n <option *ngFor=\"let floor of floorsPerSpace\" [ngValue]=\"floor\">{{ floor.name}}</option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu zone\" [(ngModel)]=\"selectedZone\"\n (ngModelChange)=\"onZoneClick()\">\n <option [ngValue]=\"null\" selected>{{'Zone' | translate}}</option>\n <option *ngFor=\"let zone of zonesPerFloor\" [ngValue]=\"zone\"><span\n *ngIf=\"zone.code_ref\">{{zone.code_ref}}_</span>{{zone.name}}</option>\n </select>\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" [(ngModel)]=\"selectedChildZone\"\n *ngIf=\"childrenZones && childrenZones.length>0\" (ngModelChange)=\"onChildZoneClick()\">\n <option [ngValue]=\"null\" selected disabled>{{'Zone' | translate}}</option>\n <option *ngFor=\"let zone of childrenZones\" [ngValue]=\"zone\">{{ zone.name}}</option>\n </select>\n <button (click)=\"goTo()\"\n class=\"btn btn-outline-primary rounded-pill mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d d-none d-lg-block\"\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\n </button>\n </div>\n <div class=\"row align-items-center justify-content-center ml-0 p-1\" *ngIf=\"showLocation()\">\n <p class=\"fw-bold lh-base align-middle text-center\">\n {{ showLocation() }}\n </p>\n </div>\n <div class=\"row align-items-center justify-content-center ml-0 p-1 d-block d-lg-none\">\n <button (click)=\"goTo()\"\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d\"\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\n </button>\n </div>\n </div>\n </div>\n</nav>", styles: [":host{position:sticky;top:0;height:123px}.navbar{z-index:200;padding:.4rem 1rem}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0}@media (min-width: 992px){.flex-lg-fill-unset{flex:unset!important}}.form-control{width:100%;min-width:80px;max-width:18%}.location{width:auto;max-width:35%}.floor,.zone{width:auto;max-width:30%}button{color:#fff;padding:5px 10px;font-size:1.1em}.navbar-toggler{margin-right:1em}.select-menu{max-width:inherit}.btn-3d .icon-go-to-3d{width:30px;height:30px;background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0A<style type=\"text/css\">%0A%09.st0{fill:%23565656;}%0A<\\/style>%0A<g>%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0A%09%09/>%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0A</g>%0A</svg>%0A');border:none;vertical-align:middle;fill:var(--smarterplan-primary)}.btn-3d:hover:enabled .icon-go-to-3d{background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0A<style type=\"text/css\">%0A%09.st0{fill:%23FFFFFF;}%0A<\\/style>%0A<g>%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0A%09%09/>%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0A</g>%0A</svg>%0A')}.btn-3d[disabled]:hover .icon-go-to-3d{fill:var(--smarterplan-primary)}.outer_circle{background-color:#ebebeb;border-radius:50%;width:32px;height:32px;padding:1px}@media (max-width: 767px){.navbar{padding:.2rem .5rem}.form-control,.location,.floor,.zone{max-width:100%;margin-bottom:15px}input,select{margin-right:0;margin-bottom:15px}}\n"] }]
|
|
15149
|
+
args: [{ selector: 'lib-navigation-bar', template: "<nav class=\"navbar navbar-expand-md navbar-dark navbar-inverse second-nav\">\r\n <div class=\"d-flex w-100\">\r\n <div #navbarSelectMenu class=\"w-100\" id=\"nav-item-container-blue\">\r\n <div class=\"d-flex flex-column flex-md-row p-1 mt-2\">\r\n <select class=\"form-control flex-fill flex-lg-fill-unset location select-menu\"\r\n [(ngModel)]=\"selectedLocation\" (ngModelChange)=\"onLocationClick()\">\r\n <option [ngValue]=\"null\" selected>{{ 'Location' | translate }}</option>\r\n <option *ngFor=\"let loc of locations; index as index\" [ngValue]=\"loc\"> {{ loc.name }}</option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" (change)=\"onVisitClick($event)\"\r\n *ngIf=\"visitsPerSpace && visitsPerSpace.length > 1\">\r\n <option value=\"default\" selected disabled hidden>{{'Visit' | translate}}</option>\r\n <option *ngFor=\"let visit of visitsPerSpace; index as index\" value=\"{{index}}\">{{ visit.name}}\r\n </option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset floor select-menu\" [(ngModel)]=\"selectedFloor\"\r\n (ngModelChange)=\"onFloorClick()\">\r\n <option [ngValue]=\"null\" selected>{{'Floor' | translate}}</option>\r\n <option *ngFor=\"let floor of floorsPerSpace\" [ngValue]=\"floor\">{{ floor.name}}</option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu zone\" [(ngModel)]=\"selectedZone\"\r\n (ngModelChange)=\"onZoneClick()\">\r\n <option [ngValue]=\"null\" selected>{{'Zone' | translate}}</option>\r\n <option *ngFor=\"let zone of zonesPerFloor\" [ngValue]=\"zone\"><span\r\n *ngIf=\"zone.code_ref\">{{zone.code_ref}}_</span>{{zone.name}}</option>\r\n </select>\r\n <select class=\"form-control flex-fill flex-lg-fill-unset select-menu\" [(ngModel)]=\"selectedChildZone\"\r\n *ngIf=\"childrenZones && childrenZones.length>0\" (ngModelChange)=\"onChildZoneClick()\">\r\n <option [ngValue]=\"null\" selected disabled>{{'Zone' | translate}}</option>\r\n <option *ngFor=\"let zone of childrenZones\" [ngValue]=\"zone\">{{ zone.name}}</option>\r\n </select>\r\n <button (click)=\"goTo()\"\r\n class=\"btn btn-outline-primary rounded-pill mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d d-none d-lg-block\"\r\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\r\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\r\n </button>\r\n </div>\r\n <div class=\"row align-items-center justify-content-center ml-0 p-1\" *ngIf=\"showLocation()\">\r\n <p class=\"fw-bold lh-base align-middle text-center\">\r\n {{ showLocation() }}\r\n </p>\r\n </div>\r\n <div class=\"row align-items-center justify-content-center ml-0 p-1 d-block d-lg-none\">\r\n <button (click)=\"goTo()\"\r\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center btn-3d\"\r\n [disabled]=\"!selectedLocation || !selectedModel3d || !canGo()\">\r\n <i class=\"icon-go-to-3d d-inline-block\"></i> {{'3D visit' | translate}}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</nav>", styles: [":host{position:sticky;top:0;height:123px}.navbar{z-index:200;padding:.4rem 1rem}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0}@media (min-width: 992px){.flex-lg-fill-unset{flex:unset!important}}.form-control{width:100%;min-width:80px;max-width:18%}.location{width:auto;max-width:35%}.floor,.zone{width:auto;max-width:30%}button{color:#fff;padding:5px 10px;font-size:1.1em}.navbar-toggler{margin-right:1em}.select-menu{max-width:inherit}.btn-3d .icon-go-to-3d{width:30px;height:30px;background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0D%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0D%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0D%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0D%0A<style type=\"text/css\">%0D%0A%09.st0{fill:%23565656;}%0D%0A<\\/style>%0D%0A<g>%0D%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0D%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0D%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0D%0A%09%09/>%0D%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0D%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0D%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0D%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0D%0A</g>%0D%0A</svg>%0D%0A');border:none;vertical-align:middle;fill:var(--smarterplan-primary)}.btn-3d:hover:enabled .icon-go-to-3d{background:url('data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?>%0D%0A<!-- Generator: Adobe Illustrator 25.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->%0D%0A<svg version=\"1.1\" id=\"Calque_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"%0D%0A%09 viewBox=\"0 0 60 60\" style=\"enable-background:new 0 0 60 60;\" xml:space=\"preserve\">%0D%0A<style type=\"text/css\">%0D%0A%09.st0{fill:%23FFFFFF;}%0D%0A<\\/style>%0D%0A<g>%0D%0A%09<path class=\"st0\" d=\"M43.9,32.1V17.7c0-0.4-0.2-0.7-0.5-0.9l-12.8-8c-0.2-0.1-0.4-0.2-0.6-0.2c-0.2,0-0.4,0.1-0.6,0.2l-12.8,8%0D%0A%09%09c-0.3,0.2-0.5,0.5-0.5,0.9v14.4c0,0.4,0.2,0.7,0.5,0.9l12.8,8c0.3,0.2,0.8,0.2,1.1,0l12.8-8C43.7,32.8,43.9,32.5,43.9,32.1z%0D%0A%09%09 M28.9,38.2l-10.7-6.7v-12l10.7,6.7V38.2z M30,24.4l-10.8-6.8L30,10.9l10.8,6.8L30,24.4z M41.8,31.5l-10.7,6.7v-12l10.7-6.7V31.5z\"%0D%0A%09%09/>%0D%0A%09<path class=\"st0\" d=\"M56.1,29.3l-10.3-6.8v2l1.4,1v0l0.8,0.5l0,0l7,4.8c0.3,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8l-6.8,4.7%0D%0A%09%09l0,0l-0.9,0.7v0l-2.9,2v0l-13.8,9.6c-0.3,0.2-0.8,0.2-1.1,0l-14.2-9.8l-2.6-1.8v0L5,32.4c-0.3-0.2-0.4-0.5-0.4-0.8%0D%0A%09%09c0-0.3,0.2-0.6,0.4-0.8l0,0l7.3-5l0,0l0.5-0.3v0l1.4-1v-2L3.9,29.3c-0.8,0.5-1.2,1.4-1.2,2.4c0,0.9,0.5,1.8,1.2,2.4l8.8,6.1v0%0D%0A%09%09l4.5,3.1l11.2,7.7c1,0.7,2.3,0.7,3.3,0l13.7-9.5l1.9-1.3v0l8.8-6.1c0.8-0.5,1.2-1.4,1.2-2.4S56.9,29.8,56.1,29.3z\"/>%0D%0A</g>%0D%0A</svg>%0D%0A')}.btn-3d[disabled]:hover .icon-go-to-3d{fill:var(--smarterplan-primary)}.outer_circle{background-color:#ebebeb;border-radius:50%;width:32px;height:32px;padding:1px}@media (max-width: 767px){.navbar{padding:.2rem .5rem}.form-control,.location,.floor,.zone{max-width:100%;margin-bottom:15px}input,select{margin-right:0;margin-bottom:15px}}\n"] }]
|
|
15001
15150
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
15002
15151
|
type: Inject,
|
|
15003
15152
|
args: ['currentAwsKinesisAnalyticsService']
|
|
@@ -15266,11 +15415,11 @@ class MenuBarComponent {
|
|
|
15266
15415
|
}
|
|
15267
15416
|
}
|
|
15268
15417
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MenuBarComponent, deps: [{ token: i1$1.Router }, { token: LocaleService }, { token: BaseUserService }, { token: NavigatorService }, { token: SupportService }, { token: BaseVisibilityService }, { token: i1$2.NgbCalendar }, { token: i1$2.NgbDateParserFormatter }, { token: FilterService }, { token: AmplifyCacheService }], target: i0.ɵɵFactoryTarget.Component });
|
|
15269
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: MenuBarComponent, selector: "lib-menu-bar", inputs: { cacheName: "cacheName" }, ngImport: i0, template: "<div id=\"menu-bar\">\n <div *ngIf=\"!isVisitor\">\n <nav class=\"navbar navbar-expand-md navbar-light p-0\">\n <div class=\"container-fluid\" *ngIf=\"isVisible\">\n <div class=\"navbar-brand order-md-0\" [routerLink]=\"['/dashboard']\">\n <img alt=\"SmarterPlan\" src=\"../assets/images/logos/logo-immo.png\">\n </div>\n <div class=\"ms-auto nav-item dropdown profile_pic-container order-md-2\">\n <div class=\"profile_pic dropdown-toggle\" data-testid=\"dropdown-menu-button\" data-bs-toggle=\"dropdown\">\n <lib-avatar></lib-avatar>\n </div>\n <div class=\"dropdown-menu dropdown-menu-right\">\n <p *ngIf=\"user && mission\" class=\"p-2\">\n <span class=\"username\">{{ user.displayName }}</span><br />\n <span class=\"user-role\">{{ mission.role }}</span><br />\n <span class=\"org\">{{ mission.organisation ? mission.organisation.name : \"No organisation\" |\n translate}}</span>\n </p>\n <div class=\"dropdown-divider\"></div>\n <!-- <a class=\"dropdown-item\" routerLink=\"/debug\" *ngIf=\"isManager\">Debug</a> -->\n <a class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</a>\n <a class=\"dropdown-item\" routerLink=\"/dashboard\">{{'Data management' | translate}}</a>\n <a class=\"dropdown-item\" data-testid=\"user-management-btn\" routerLink=\"/admin\" *ngIf=\"isManager\">\n {{'Users management' | translate}}</a>\n <a class=\"dropdown-item\" routerLink=\"/profile\">\n {{'Profile' | translate}}</a>\n <div class=\"dropdown-divider\"></div>\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\n translate}}</button>\n </div>\n </div>\n <button class=\"navbar-toggler order-md-1\" (click)=\"navbarCollapse.toggle()\" type=\"button\"\n [attr.aria-expanded]=\"!isCollapsed\" aria-controls=\"navbar-collapse\">\n <span class=\"navbar-toggler-icon\"></span>\n </button>\n <div class=\"navbar-collapse order-md-1\" #navbarCollapse=\"ngbCollapse\" [(ngbCollapse)]=\"isCollapsed\"\n [animation]=\"false\">\n <form\n class=\"form-inline m-0 mt-2 form-container d-flex justify-content-start align-items-start align-items-md-center flex-column flex-md-row flex-nowrap filters-menu-block\">\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\n <input class=\"form-control search-button m-1\" placeholder=\"keyword\" id=\"mainSearchBar\" type=\"text\">\n <button class=\"btn btn-outline-primary rounded-pill m-1 w-fit-content h-fit-content align-self-md-center\"\n (click)=\"onSubmit()\">{{'Search' |\n translate}}</button>\n </div>\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\n <div class=\"input-group date-selector m-1\">\n <input #dpFromDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpFromDate\"\n [value]=\"fromDate | formatDateNumberToDigits\"\n (input)=\"fromDate = validateInput(fromDate, dpFromDate.value)\">\n <div class=\"input-group-append\">\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\n type=\"button\"></button>\n </div>\n </div>\n <input name=\"datepicker\" class=\"form-control visually-hidden\" ngbDatepicker #datepicker=\"ngbDatepicker\"\n [autoClose]=\"'outside'\" (dateSelect)=\"onDateSelection($event)\" [displayMonths]=\"2\" [dayTemplate]=\"t\"\n outsideDays=\"hidden\" [startDate]=\"fromDate || calendar.getToday()\" [container]=\"'body'\" tabindex=\"-1\">\n <ng-template #t let-date let-focused=\"focused\">\n <span class=\"custom-day\" [class.focused]=\"focused\" [class.range]=\"isRange(date)\"\n [class.faded]=\"isHovered(date) || isInside(date)\" (mouseenter)=\"hoveredDate = date\"\n (mouseleave)=\"hoveredDate = null\">\n {{ date.day }}\n </span>\n </ng-template>\n <span class=\"ms-1 p-2\">{{'to' | translate}}</span>\n <div class=\"input-group date-selector m-1\">\n <input #dpToDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpToDate\"\n [value]=\"toDate | formatDateNumberToDigits\" (input)=\"toDate = validateInput(toDate, dpToDate.value)\">\n <div class=\"input-group-append\">\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\n type=\"button\"></button>\n </div>\n </div>\n </div>\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-1 justify-content-evenly\">\n <button\n class=\"btn btn-primary rounded-pill ms-1 w-25 w-md-fit-content h-md-fit-content align-self-md-center\"\n type=\"button\" (click)=\"onApply()\" *ngIf=\"!isDateFilterApplied || dateChanged\">\n {{'Apply' | translate}}\n </button>\n <span\n class=\"appliedText ms-1 py-2 align-self-md-center pb-md-0 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\n *ngIf=\"isDateFilterApplied && !dateChanged\">\n <span class=\"iconify\" data-icon=\"ion:checkmark\" data-width=\"15\" data-height=\"15\"></span>\n {{\"Applied\" | translate}}\n </span>\n <button\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\n type=\"button\" (click)=\"onClearDates()\">{{'Clear'\n |\n translate}}</button>\n <div\n class=\"change-position-button align-self-end pb-2 align-self-md-center mx-2 pb-md-0 flex-nowrap w-25 w-md-fit-content h-md-fit-content\">\n <input type=\"checkbox\" class=\"btn-check\" id=\"btn-check-outlined\" autocomplete=\"off\">\n <label class=\"link-primary cursor-pointer text-decoration-underline\" (click)=\"onChangePositionClick()\"\n for=\"btn-check-outlined\">{{\n (isChangePositionVisible ? \"Close\" : \"Move to\") | translate }}</label>\n </div>\n </div>\n </form>\n </div>\n </div>\n </nav>\n <lib-navigation-bar *ngIf=\"isVisible && isChangePositionVisible\"></lib-navigation-bar>\n </div>\n <div *ngIf=\"isVisitor && isVisible\">\n <div class=\"visitor-div\">\n <div class=\"logo-container\" data-testid=\"dropdown-menu-button\">\n <img class=\"img-logo\" alt=\"SmarterPlanLogo\" src=\"../assets/images/logos/logo-reserve.png\">\n </div>\n <div class=\"avatar-container-menu\">\n <div class=\"profile_pic dropdown-toggle cursor-pointer\" data-bs-toggle=\"dropdown\">\n <lib-avatar></lib-avatar>\n </div>\n <div class=\"dropdown-menu dropdown-menu-right\">\n <button class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</button>\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\n translate}}</button>\n </div>\n </div>\n </div>\n </div>\n</div>", styles: ["#menu-bar{position:sticky;top:0;z-index:200}.navbar{z-index:200}.navbar-brand{padding-top:5px;padding-bottom:5px;cursor:pointer}.navbar-brand img{height:70px}.profile_pic{border-radius:50%;height:45px;width:45px;margin:8px;border:.2px solid rgb(150,150,150)}.navbar-nav .profile-pic-container .dropdown-menu{position:absolute}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}.profile_pic.dropdown-toggle:after{display:none}.navbar-light{border-bottom:1px solid var(--smarterplan-primary);background-color:#fff}.navbar form{width:100%;margin:0;padding:0}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0;width:auto}button{padding:5px 10px}button:disabled,button[disabled]{color:#c04f4f}.navbar-toggler{margin-right:1em}.icon{height:40px;width:40px;color:var(--smarterplan-primary)}.search-button-container{width:auto;align-items:stretch;justify-items:start}.search-button-container .search-button{width:auto;border-radius:1rem!important}.visitor-div{background-color:var(--smarterplan-primary);height:60px;display:flex;justify-content:space-between}.profile_pic-container{margin-right:1em}.logo-container,.img-logo{height:100%}.change-position-button{margin-left:2rem}.change-position-button label,.change-position-button .btn-check:checked,.change-position-button .btn-check:focus,.change-position-button .btn-outline-primary,.change-position-button .btn{box-shadow:none!important;outline:0}.change-position-button label{border-radius:16px}.change-position-button .btn-check:checked+.btn{background-color:var(--smarterplan-primary);color:#fff!important}.filters-menu-block{width:auto}@media (min-width: 1200px){.navbar-brand img{height:100px}.profile_pic{height:60px;width:60px;margin:15px}}@media (min-width: 992px) and (max-width: 1199.98px){.navbar-brand img{height:80px}.profile_pic{height:50px;width:50px;margin:12px}}@media (min-width: 768px) and (max-width: 991.98px){.navbar-brand img{height:60px}.profile_pic{height:40px;width:40px;margin:10px}}@media (max-width: 767.98px){.navbar-brand img{height:50px}.profile_pic{height:30px;width:30px;margin:8px}.search-button-container,.filters-menu-block{width:100%}}.form-container{margin:.5rem 0}.navbar-collapse.show{display:flex;padding-bottom:.5rem}.hidden{width:0;margin:0;border:none;padding:0}.custom-day{text-align:center;padding:.185rem .25rem;display:inline-block;height:2rem;width:2rem}.custom-day.focused{background-color:#e6e6e6}.custom-day.range,.custom-day:hover{background-color:var(--smarterplan-primary-lighter);color:#fff}.custom-day.faded{background-color:var(--smarterplan-primary-transparent)}.calendar{height:100%}.appliedText,.appliedText span{color:var(--smarterplan-primary)}@media (max-width: 767px){.form-inline{flex-direction:column}}.hidden{opacity:0}.date-selector{flex-wrap:nowrap}.date-selector input{min-width:80px;margin:0}@media (min-width: 768px){.w-md-fit-content{width:fit-content!important}.h-md-content{height:fit-content!important}}\n"], dependencies: [{ kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1$2.NgbCollapse, selector: "[ngbCollapse]", inputs: ["animation", "ngbCollapse", "horizontal"], outputs: ["ngbCollapseChange", "shown", "hidden"], exportAs: ["ngbCollapse"] }, { kind: "directive", type: i1$2.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }, { kind: "component", type: AvatarComponent, selector: "lib-avatar", inputs: ["size", "userID"] }, { kind: "component", type: NavigationBarComponent, selector: "lib-navigation-bar" }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "pipe", type: FormatDateNumberToDigitsPipe, name: "formatDateNumberToDigits" }] });
|
|
15418
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: MenuBarComponent, selector: "lib-menu-bar", inputs: { cacheName: "cacheName" }, ngImport: i0, template: "<div id=\"menu-bar\">\r\n <div *ngIf=\"!isVisitor\">\r\n <nav class=\"navbar navbar-expand-md navbar-light p-0\">\r\n <div class=\"container-fluid\" *ngIf=\"isVisible\">\r\n <div class=\"navbar-brand order-md-0\" [routerLink]=\"['/dashboard']\">\r\n <img alt=\"SmarterPlan\" src=\"../assets/images/logos/logo-immo.png\">\r\n </div>\r\n <div class=\"ms-auto nav-item dropdown profile_pic-container order-md-2\">\r\n <div class=\"profile_pic dropdown-toggle\" data-testid=\"dropdown-menu-button\" data-bs-toggle=\"dropdown\">\r\n <lib-avatar></lib-avatar>\r\n </div>\r\n <div class=\"dropdown-menu dropdown-menu-right\">\r\n <p *ngIf=\"user && mission\" class=\"p-2\">\r\n <span class=\"username\">{{ user.displayName }}</span><br />\r\n <span class=\"user-role\">{{ mission.role }}</span><br />\r\n <span class=\"org\">{{ mission.organisation ? mission.organisation.name : \"No organisation\" |\r\n translate}}</span>\r\n </p>\r\n <div class=\"dropdown-divider\"></div>\r\n <!-- <a class=\"dropdown-item\" routerLink=\"/debug\" *ngIf=\"isManager\">Debug</a> -->\r\n <a class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</a>\r\n <a class=\"dropdown-item\" routerLink=\"/dashboard\">{{'Data management' | translate}}</a>\r\n <a class=\"dropdown-item\" data-testid=\"user-management-btn\" routerLink=\"/admin\" *ngIf=\"isManager\">\r\n {{'Users management' | translate}}</a>\r\n <a class=\"dropdown-item\" routerLink=\"/profile\">\r\n {{'Profile' | translate}}</a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\r\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\r\n translate}}</button>\r\n </div>\r\n </div>\r\n <button class=\"navbar-toggler order-md-1\" (click)=\"navbarCollapse.toggle()\" type=\"button\"\r\n [attr.aria-expanded]=\"!isCollapsed\" aria-controls=\"navbar-collapse\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n <div class=\"navbar-collapse order-md-1\" #navbarCollapse=\"ngbCollapse\" [(ngbCollapse)]=\"isCollapsed\"\r\n [animation]=\"false\">\r\n <form\r\n class=\"form-inline m-0 mt-2 form-container d-flex justify-content-start align-items-start align-items-md-center flex-column flex-md-row flex-nowrap filters-menu-block\">\r\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\r\n <input class=\"form-control search-button m-1\" placeholder=\"keyword\" id=\"mainSearchBar\" type=\"text\">\r\n <button class=\"btn btn-outline-primary rounded-pill m-1 w-fit-content h-fit-content align-self-md-center\"\r\n (click)=\"onSubmit()\">{{'Search' |\r\n translate}}</button>\r\n </div>\r\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\r\n <div class=\"input-group date-selector m-1\">\r\n <input #dpFromDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpFromDate\"\r\n [value]=\"fromDate | formatDateNumberToDigits\"\r\n (input)=\"fromDate = validateInput(fromDate, dpFromDate.value)\">\r\n <div class=\"input-group-append\">\r\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\r\n type=\"button\"></button>\r\n </div>\r\n </div>\r\n <input name=\"datepicker\" class=\"form-control visually-hidden\" ngbDatepicker #datepicker=\"ngbDatepicker\"\r\n [autoClose]=\"'outside'\" (dateSelect)=\"onDateSelection($event)\" [displayMonths]=\"2\" [dayTemplate]=\"t\"\r\n outsideDays=\"hidden\" [startDate]=\"fromDate || calendar.getToday()\" [container]=\"'body'\" tabindex=\"-1\">\r\n <ng-template #t let-date let-focused=\"focused\">\r\n <span class=\"custom-day\" [class.focused]=\"focused\" [class.range]=\"isRange(date)\"\r\n [class.faded]=\"isHovered(date) || isInside(date)\" (mouseenter)=\"hoveredDate = date\"\r\n (mouseleave)=\"hoveredDate = null\">\r\n {{ date.day }}\r\n </span>\r\n </ng-template>\r\n <span class=\"ms-1 p-2\">{{'to' | translate}}</span>\r\n <div class=\"input-group date-selector m-1\">\r\n <input #dpToDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpToDate\"\r\n [value]=\"toDate | formatDateNumberToDigits\" (input)=\"toDate = validateInput(toDate, dpToDate.value)\">\r\n <div class=\"input-group-append\">\r\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\r\n type=\"button\"></button>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-1 justify-content-evenly\">\r\n <button\r\n class=\"btn btn-primary rounded-pill ms-1 w-25 w-md-fit-content h-md-fit-content align-self-md-center\"\r\n type=\"button\" (click)=\"onApply()\" *ngIf=\"!isDateFilterApplied || dateChanged\">\r\n {{'Apply' | translate}}\r\n </button>\r\n <span\r\n class=\"appliedText ms-1 py-2 align-self-md-center pb-md-0 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\r\n *ngIf=\"isDateFilterApplied && !dateChanged\">\r\n <span class=\"iconify\" data-icon=\"ion:checkmark\" data-width=\"15\" data-height=\"15\"></span>\r\n {{\"Applied\" | translate}}\r\n </span>\r\n <button\r\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\r\n type=\"button\" (click)=\"onClearDates()\">{{'Clear'\r\n |\r\n translate}}</button>\r\n <div\r\n class=\"change-position-button align-self-end pb-2 align-self-md-center mx-2 pb-md-0 flex-nowrap w-25 w-md-fit-content h-md-fit-content\">\r\n <input type=\"checkbox\" class=\"btn-check\" id=\"btn-check-outlined\" autocomplete=\"off\">\r\n <label class=\"link-primary cursor-pointer text-decoration-underline\" (click)=\"onChangePositionClick()\"\r\n for=\"btn-check-outlined\">{{\r\n (isChangePositionVisible ? \"Close\" : \"Move to\") | translate }}</label>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n </nav>\r\n <lib-navigation-bar *ngIf=\"isVisible && isChangePositionVisible\"></lib-navigation-bar>\r\n </div>\r\n <div *ngIf=\"isVisitor && isVisible\">\r\n <div class=\"visitor-div\">\r\n <div class=\"logo-container\" data-testid=\"dropdown-menu-button\">\r\n <img class=\"img-logo\" alt=\"SmarterPlanLogo\" src=\"../assets/images/logos/logo-reserve.png\">\r\n </div>\r\n <div class=\"avatar-container-menu\">\r\n <div class=\"profile_pic dropdown-toggle cursor-pointer\" data-bs-toggle=\"dropdown\">\r\n <lib-avatar></lib-avatar>\r\n </div>\r\n <div class=\"dropdown-menu dropdown-menu-right\">\r\n <button class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</button>\r\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\r\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\r\n translate}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: ["#menu-bar{position:sticky;top:0;z-index:200}.navbar{z-index:200}.navbar-brand{padding-top:5px;padding-bottom:5px;cursor:pointer}.navbar-brand img{height:70px}.profile_pic{border-radius:50%;height:45px;width:45px;margin:8px;border:.2px solid rgb(150,150,150)}.navbar-nav .profile-pic-container .dropdown-menu{position:absolute}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}.profile_pic.dropdown-toggle:after{display:none}.navbar-light{border-bottom:1px solid var(--smarterplan-primary);background-color:#fff}.navbar form{width:100%;margin:0;padding:0}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0;width:auto}button{padding:5px 10px}button:disabled,button[disabled]{color:#c04f4f}.navbar-toggler{margin-right:1em}.icon{height:40px;width:40px;color:var(--smarterplan-primary)}.search-button-container{width:auto;align-items:stretch;justify-items:start}.search-button-container .search-button{width:auto;border-radius:1rem!important}.visitor-div{background-color:var(--smarterplan-primary);height:60px;display:flex;justify-content:space-between}.profile_pic-container{margin-right:1em}.logo-container,.img-logo{height:100%}.change-position-button{margin-left:2rem}.change-position-button label,.change-position-button .btn-check:checked,.change-position-button .btn-check:focus,.change-position-button .btn-outline-primary,.change-position-button .btn{box-shadow:none!important;outline:0}.change-position-button label{border-radius:16px}.change-position-button .btn-check:checked+.btn{background-color:var(--smarterplan-primary);color:#fff!important}.filters-menu-block{width:auto}@media (min-width: 1200px){.navbar-brand img{height:100px}.profile_pic{height:60px;width:60px;margin:15px}}@media (min-width: 992px) and (max-width: 1199.98px){.navbar-brand img{height:80px}.profile_pic{height:50px;width:50px;margin:12px}}@media (min-width: 768px) and (max-width: 991.98px){.navbar-brand img{height:60px}.profile_pic{height:40px;width:40px;margin:10px}}@media (max-width: 767.98px){.navbar-brand img{height:50px}.profile_pic{height:30px;width:30px;margin:8px}.search-button-container,.filters-menu-block{width:100%}}.form-container{margin:.5rem 0}.navbar-collapse.show{display:flex;padding-bottom:.5rem}.hidden{width:0;margin:0;border:none;padding:0}.custom-day{text-align:center;padding:.185rem .25rem;display:inline-block;height:2rem;width:2rem}.custom-day.focused{background-color:#e6e6e6}.custom-day.range,.custom-day:hover{background-color:var(--smarterplan-primary-lighter);color:#fff}.custom-day.faded{background-color:var(--smarterplan-primary-transparent)}.calendar{height:100%}.appliedText,.appliedText span{color:var(--smarterplan-primary)}@media (max-width: 767px){.form-inline{flex-direction:column}}.hidden{opacity:0}.date-selector{flex-wrap:nowrap}.date-selector input{min-width:80px;margin:0}@media (min-width: 768px){.w-md-fit-content{width:fit-content!important}.h-md-content{height:fit-content!important}}\n"], dependencies: [{ kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1$2.NgbCollapse, selector: "[ngbCollapse]", inputs: ["animation", "ngbCollapse", "horizontal"], outputs: ["ngbCollapseChange", "shown", "hidden"], exportAs: ["ngbCollapse"] }, { kind: "directive", type: i1$2.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }, { kind: "component", type: AvatarComponent, selector: "lib-avatar", inputs: ["size", "userID"] }, { kind: "component", type: NavigationBarComponent, selector: "lib-navigation-bar" }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "pipe", type: FormatDateNumberToDigitsPipe, name: "formatDateNumberToDigits" }] });
|
|
15270
15419
|
}
|
|
15271
15420
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MenuBarComponent, decorators: [{
|
|
15272
15421
|
type: Component,
|
|
15273
|
-
args: [{ selector: 'lib-menu-bar', template: "<div id=\"menu-bar\">\n <div *ngIf=\"!isVisitor\">\n <nav class=\"navbar navbar-expand-md navbar-light p-0\">\n <div class=\"container-fluid\" *ngIf=\"isVisible\">\n <div class=\"navbar-brand order-md-0\" [routerLink]=\"['/dashboard']\">\n <img alt=\"SmarterPlan\" src=\"../assets/images/logos/logo-immo.png\">\n </div>\n <div class=\"ms-auto nav-item dropdown profile_pic-container order-md-2\">\n <div class=\"profile_pic dropdown-toggle\" data-testid=\"dropdown-menu-button\" data-bs-toggle=\"dropdown\">\n <lib-avatar></lib-avatar>\n </div>\n <div class=\"dropdown-menu dropdown-menu-right\">\n <p *ngIf=\"user && mission\" class=\"p-2\">\n <span class=\"username\">{{ user.displayName }}</span><br />\n <span class=\"user-role\">{{ mission.role }}</span><br />\n <span class=\"org\">{{ mission.organisation ? mission.organisation.name : \"No organisation\" |\n translate}}</span>\n </p>\n <div class=\"dropdown-divider\"></div>\n <!-- <a class=\"dropdown-item\" routerLink=\"/debug\" *ngIf=\"isManager\">Debug</a> -->\n <a class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</a>\n <a class=\"dropdown-item\" routerLink=\"/dashboard\">{{'Data management' | translate}}</a>\n <a class=\"dropdown-item\" data-testid=\"user-management-btn\" routerLink=\"/admin\" *ngIf=\"isManager\">\n {{'Users management' | translate}}</a>\n <a class=\"dropdown-item\" routerLink=\"/profile\">\n {{'Profile' | translate}}</a>\n <div class=\"dropdown-divider\"></div>\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\n translate}}</button>\n </div>\n </div>\n <button class=\"navbar-toggler order-md-1\" (click)=\"navbarCollapse.toggle()\" type=\"button\"\n [attr.aria-expanded]=\"!isCollapsed\" aria-controls=\"navbar-collapse\">\n <span class=\"navbar-toggler-icon\"></span>\n </button>\n <div class=\"navbar-collapse order-md-1\" #navbarCollapse=\"ngbCollapse\" [(ngbCollapse)]=\"isCollapsed\"\n [animation]=\"false\">\n <form\n class=\"form-inline m-0 mt-2 form-container d-flex justify-content-start align-items-start align-items-md-center flex-column flex-md-row flex-nowrap filters-menu-block\">\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\n <input class=\"form-control search-button m-1\" placeholder=\"keyword\" id=\"mainSearchBar\" type=\"text\">\n <button class=\"btn btn-outline-primary rounded-pill m-1 w-fit-content h-fit-content align-self-md-center\"\n (click)=\"onSubmit()\">{{'Search' |\n translate}}</button>\n </div>\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\n <div class=\"input-group date-selector m-1\">\n <input #dpFromDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpFromDate\"\n [value]=\"fromDate | formatDateNumberToDigits\"\n (input)=\"fromDate = validateInput(fromDate, dpFromDate.value)\">\n <div class=\"input-group-append\">\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\n type=\"button\"></button>\n </div>\n </div>\n <input name=\"datepicker\" class=\"form-control visually-hidden\" ngbDatepicker #datepicker=\"ngbDatepicker\"\n [autoClose]=\"'outside'\" (dateSelect)=\"onDateSelection($event)\" [displayMonths]=\"2\" [dayTemplate]=\"t\"\n outsideDays=\"hidden\" [startDate]=\"fromDate || calendar.getToday()\" [container]=\"'body'\" tabindex=\"-1\">\n <ng-template #t let-date let-focused=\"focused\">\n <span class=\"custom-day\" [class.focused]=\"focused\" [class.range]=\"isRange(date)\"\n [class.faded]=\"isHovered(date) || isInside(date)\" (mouseenter)=\"hoveredDate = date\"\n (mouseleave)=\"hoveredDate = null\">\n {{ date.day }}\n </span>\n </ng-template>\n <span class=\"ms-1 p-2\">{{'to' | translate}}</span>\n <div class=\"input-group date-selector m-1\">\n <input #dpToDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpToDate\"\n [value]=\"toDate | formatDateNumberToDigits\" (input)=\"toDate = validateInput(toDate, dpToDate.value)\">\n <div class=\"input-group-append\">\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\n type=\"button\"></button>\n </div>\n </div>\n </div>\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-1 justify-content-evenly\">\n <button\n class=\"btn btn-primary rounded-pill ms-1 w-25 w-md-fit-content h-md-fit-content align-self-md-center\"\n type=\"button\" (click)=\"onApply()\" *ngIf=\"!isDateFilterApplied || dateChanged\">\n {{'Apply' | translate}}\n </button>\n <span\n class=\"appliedText ms-1 py-2 align-self-md-center pb-md-0 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\n *ngIf=\"isDateFilterApplied && !dateChanged\">\n <span class=\"iconify\" data-icon=\"ion:checkmark\" data-width=\"15\" data-height=\"15\"></span>\n {{\"Applied\" | translate}}\n </span>\n <button\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\n type=\"button\" (click)=\"onClearDates()\">{{'Clear'\n |\n translate}}</button>\n <div\n class=\"change-position-button align-self-end pb-2 align-self-md-center mx-2 pb-md-0 flex-nowrap w-25 w-md-fit-content h-md-fit-content\">\n <input type=\"checkbox\" class=\"btn-check\" id=\"btn-check-outlined\" autocomplete=\"off\">\n <label class=\"link-primary cursor-pointer text-decoration-underline\" (click)=\"onChangePositionClick()\"\n for=\"btn-check-outlined\">{{\n (isChangePositionVisible ? \"Close\" : \"Move to\") | translate }}</label>\n </div>\n </div>\n </form>\n </div>\n </div>\n </nav>\n <lib-navigation-bar *ngIf=\"isVisible && isChangePositionVisible\"></lib-navigation-bar>\n </div>\n <div *ngIf=\"isVisitor && isVisible\">\n <div class=\"visitor-div\">\n <div class=\"logo-container\" data-testid=\"dropdown-menu-button\">\n <img class=\"img-logo\" alt=\"SmarterPlanLogo\" src=\"../assets/images/logos/logo-reserve.png\">\n </div>\n <div class=\"avatar-container-menu\">\n <div class=\"profile_pic dropdown-toggle cursor-pointer\" data-bs-toggle=\"dropdown\">\n <lib-avatar></lib-avatar>\n </div>\n <div class=\"dropdown-menu dropdown-menu-right\">\n <button class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</button>\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\n translate}}</button>\n </div>\n </div>\n </div>\n </div>\n</div>", styles: ["#menu-bar{position:sticky;top:0;z-index:200}.navbar{z-index:200}.navbar-brand{padding-top:5px;padding-bottom:5px;cursor:pointer}.navbar-brand img{height:70px}.profile_pic{border-radius:50%;height:45px;width:45px;margin:8px;border:.2px solid rgb(150,150,150)}.navbar-nav .profile-pic-container .dropdown-menu{position:absolute}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}.profile_pic.dropdown-toggle:after{display:none}.navbar-light{border-bottom:1px solid var(--smarterplan-primary);background-color:#fff}.navbar form{width:100%;margin:0;padding:0}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0;width:auto}button{padding:5px 10px}button:disabled,button[disabled]{color:#c04f4f}.navbar-toggler{margin-right:1em}.icon{height:40px;width:40px;color:var(--smarterplan-primary)}.search-button-container{width:auto;align-items:stretch;justify-items:start}.search-button-container .search-button{width:auto;border-radius:1rem!important}.visitor-div{background-color:var(--smarterplan-primary);height:60px;display:flex;justify-content:space-between}.profile_pic-container{margin-right:1em}.logo-container,.img-logo{height:100%}.change-position-button{margin-left:2rem}.change-position-button label,.change-position-button .btn-check:checked,.change-position-button .btn-check:focus,.change-position-button .btn-outline-primary,.change-position-button .btn{box-shadow:none!important;outline:0}.change-position-button label{border-radius:16px}.change-position-button .btn-check:checked+.btn{background-color:var(--smarterplan-primary);color:#fff!important}.filters-menu-block{width:auto}@media (min-width: 1200px){.navbar-brand img{height:100px}.profile_pic{height:60px;width:60px;margin:15px}}@media (min-width: 992px) and (max-width: 1199.98px){.navbar-brand img{height:80px}.profile_pic{height:50px;width:50px;margin:12px}}@media (min-width: 768px) and (max-width: 991.98px){.navbar-brand img{height:60px}.profile_pic{height:40px;width:40px;margin:10px}}@media (max-width: 767.98px){.navbar-brand img{height:50px}.profile_pic{height:30px;width:30px;margin:8px}.search-button-container,.filters-menu-block{width:100%}}.form-container{margin:.5rem 0}.navbar-collapse.show{display:flex;padding-bottom:.5rem}.hidden{width:0;margin:0;border:none;padding:0}.custom-day{text-align:center;padding:.185rem .25rem;display:inline-block;height:2rem;width:2rem}.custom-day.focused{background-color:#e6e6e6}.custom-day.range,.custom-day:hover{background-color:var(--smarterplan-primary-lighter);color:#fff}.custom-day.faded{background-color:var(--smarterplan-primary-transparent)}.calendar{height:100%}.appliedText,.appliedText span{color:var(--smarterplan-primary)}@media (max-width: 767px){.form-inline{flex-direction:column}}.hidden{opacity:0}.date-selector{flex-wrap:nowrap}.date-selector input{min-width:80px;margin:0}@media (min-width: 768px){.w-md-fit-content{width:fit-content!important}.h-md-content{height:fit-content!important}}\n"] }]
|
|
15422
|
+
args: [{ selector: 'lib-menu-bar', template: "<div id=\"menu-bar\">\r\n <div *ngIf=\"!isVisitor\">\r\n <nav class=\"navbar navbar-expand-md navbar-light p-0\">\r\n <div class=\"container-fluid\" *ngIf=\"isVisible\">\r\n <div class=\"navbar-brand order-md-0\" [routerLink]=\"['/dashboard']\">\r\n <img alt=\"SmarterPlan\" src=\"../assets/images/logos/logo-immo.png\">\r\n </div>\r\n <div class=\"ms-auto nav-item dropdown profile_pic-container order-md-2\">\r\n <div class=\"profile_pic dropdown-toggle\" data-testid=\"dropdown-menu-button\" data-bs-toggle=\"dropdown\">\r\n <lib-avatar></lib-avatar>\r\n </div>\r\n <div class=\"dropdown-menu dropdown-menu-right\">\r\n <p *ngIf=\"user && mission\" class=\"p-2\">\r\n <span class=\"username\">{{ user.displayName }}</span><br />\r\n <span class=\"user-role\">{{ mission.role }}</span><br />\r\n <span class=\"org\">{{ mission.organisation ? mission.organisation.name : \"No organisation\" |\r\n translate}}</span>\r\n </p>\r\n <div class=\"dropdown-divider\"></div>\r\n <!-- <a class=\"dropdown-item\" routerLink=\"/debug\" *ngIf=\"isManager\">Debug</a> -->\r\n <a class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</a>\r\n <a class=\"dropdown-item\" routerLink=\"/dashboard\">{{'Data management' | translate}}</a>\r\n <a class=\"dropdown-item\" data-testid=\"user-management-btn\" routerLink=\"/admin\" *ngIf=\"isManager\">\r\n {{'Users management' | translate}}</a>\r\n <a class=\"dropdown-item\" routerLink=\"/profile\">\r\n {{'Profile' | translate}}</a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\r\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\r\n translate}}</button>\r\n </div>\r\n </div>\r\n <button class=\"navbar-toggler order-md-1\" (click)=\"navbarCollapse.toggle()\" type=\"button\"\r\n [attr.aria-expanded]=\"!isCollapsed\" aria-controls=\"navbar-collapse\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n <div class=\"navbar-collapse order-md-1\" #navbarCollapse=\"ngbCollapse\" [(ngbCollapse)]=\"isCollapsed\"\r\n [animation]=\"false\">\r\n <form\r\n class=\"form-inline m-0 mt-2 form-container d-flex justify-content-start align-items-start align-items-md-center flex-column flex-md-row flex-nowrap filters-menu-block\">\r\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\r\n <input class=\"form-control search-button m-1\" placeholder=\"keyword\" id=\"mainSearchBar\" type=\"text\">\r\n <button class=\"btn btn-outline-primary rounded-pill m-1 w-fit-content h-fit-content align-self-md-center\"\r\n (click)=\"onSubmit()\">{{'Search' |\r\n translate}}</button>\r\n </div>\r\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-0\">\r\n <div class=\"input-group date-selector m-1\">\r\n <input #dpFromDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpFromDate\"\r\n [value]=\"fromDate | formatDateNumberToDigits\"\r\n (input)=\"fromDate = validateInput(fromDate, dpFromDate.value)\">\r\n <div class=\"input-group-append\">\r\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\r\n type=\"button\"></button>\r\n </div>\r\n </div>\r\n <input name=\"datepicker\" class=\"form-control visually-hidden\" ngbDatepicker #datepicker=\"ngbDatepicker\"\r\n [autoClose]=\"'outside'\" (dateSelect)=\"onDateSelection($event)\" [displayMonths]=\"2\" [dayTemplate]=\"t\"\r\n outsideDays=\"hidden\" [startDate]=\"fromDate || calendar.getToday()\" [container]=\"'body'\" tabindex=\"-1\">\r\n <ng-template #t let-date let-focused=\"focused\">\r\n <span class=\"custom-day\" [class.focused]=\"focused\" [class.range]=\"isRange(date)\"\r\n [class.faded]=\"isHovered(date) || isInside(date)\" (mouseenter)=\"hoveredDate = date\"\r\n (mouseleave)=\"hoveredDate = null\">\r\n {{ date.day }}\r\n </span>\r\n </ng-template>\r\n <span class=\"ms-1 p-2\">{{'to' | translate}}</span>\r\n <div class=\"input-group date-selector m-1\">\r\n <input #dpToDate class=\"form-control\" placeholder=\"dd/MM/yyyy\" name=\"dpToDate\"\r\n [value]=\"toDate | formatDateNumberToDigits\" (input)=\"toDate = validateInput(toDate, dpToDate.value)\">\r\n <div class=\"input-group-append\">\r\n <button class=\"btn btn-outline-secondary calendar\" (click)=\"datepicker.toggle()\"\r\n type=\"button\"></button>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"input-group search-button-container d-flex flex-row flex-nowrap p-0 m-1 justify-content-evenly\">\r\n <button\r\n class=\"btn btn-primary rounded-pill ms-1 w-25 w-md-fit-content h-md-fit-content align-self-md-center\"\r\n type=\"button\" (click)=\"onApply()\" *ngIf=\"!isDateFilterApplied || dateChanged\">\r\n {{'Apply' | translate}}\r\n </button>\r\n <span\r\n class=\"appliedText ms-1 py-2 align-self-md-center pb-md-0 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\r\n *ngIf=\"isDateFilterApplied && !dateChanged\">\r\n <span class=\"iconify\" data-icon=\"ion:checkmark\" data-width=\"15\" data-height=\"15\"></span>\r\n {{\"Applied\" | translate}}\r\n </span>\r\n <button\r\n class=\"btn btn-outline-primary rounded-pill w-25 mx-2 w-md-fit-content h-md-fit-content align-self-md-center\"\r\n type=\"button\" (click)=\"onClearDates()\">{{'Clear'\r\n |\r\n translate}}</button>\r\n <div\r\n class=\"change-position-button align-self-end pb-2 align-self-md-center mx-2 pb-md-0 flex-nowrap w-25 w-md-fit-content h-md-fit-content\">\r\n <input type=\"checkbox\" class=\"btn-check\" id=\"btn-check-outlined\" autocomplete=\"off\">\r\n <label class=\"link-primary cursor-pointer text-decoration-underline\" (click)=\"onChangePositionClick()\"\r\n for=\"btn-check-outlined\">{{\r\n (isChangePositionVisible ? \"Close\" : \"Move to\") | translate }}</label>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n </nav>\r\n <lib-navigation-bar *ngIf=\"isVisible && isChangePositionVisible\"></lib-navigation-bar>\r\n </div>\r\n <div *ngIf=\"isVisitor && isVisible\">\r\n <div class=\"visitor-div\">\r\n <div class=\"logo-container\" data-testid=\"dropdown-menu-button\">\r\n <img class=\"img-logo\" alt=\"SmarterPlanLogo\" src=\"../assets/images/logos/logo-reserve.png\">\r\n </div>\r\n <div class=\"avatar-container-menu\">\r\n <div class=\"profile_pic dropdown-toggle cursor-pointer\" data-bs-toggle=\"dropdown\">\r\n <lib-avatar></lib-avatar>\r\n </div>\r\n <div class=\"dropdown-menu dropdown-menu-right\">\r\n <button class=\"dropdown-item\" (click)=\"localeService.modal()\">{{'Language' | translate}}</button>\r\n <button class=\"dropdown-item\" (click)=\"openSupportForm()\">{{\"Help\" | translate}}</button>\r\n <button data-testid=\"logout-auth-btn\" class=\"dropdown-item\" (click)=\"signOut()\">{{\"Logout\" |\r\n translate}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: ["#menu-bar{position:sticky;top:0;z-index:200}.navbar{z-index:200}.navbar-brand{padding-top:5px;padding-bottom:5px;cursor:pointer}.navbar-brand img{height:70px}.profile_pic{border-radius:50%;height:45px;width:45px;margin:8px;border:.2px solid rgb(150,150,150)}.navbar-nav .profile-pic-container .dropdown-menu{position:absolute}.navbar.second-nav{z-index:199;background-color:var(--smarterplan-primary)}.profile_pic.dropdown-toggle:after{display:none}.navbar-light{border-bottom:1px solid var(--smarterplan-primary);background-color:#fff}.navbar form{width:100%;margin:0;padding:0}input,select{margin-right:15px}.select{background:transparent;border:none;color:#fff;margin:6px 20px 0;width:auto}button{padding:5px 10px}button:disabled,button[disabled]{color:#c04f4f}.navbar-toggler{margin-right:1em}.icon{height:40px;width:40px;color:var(--smarterplan-primary)}.search-button-container{width:auto;align-items:stretch;justify-items:start}.search-button-container .search-button{width:auto;border-radius:1rem!important}.visitor-div{background-color:var(--smarterplan-primary);height:60px;display:flex;justify-content:space-between}.profile_pic-container{margin-right:1em}.logo-container,.img-logo{height:100%}.change-position-button{margin-left:2rem}.change-position-button label,.change-position-button .btn-check:checked,.change-position-button .btn-check:focus,.change-position-button .btn-outline-primary,.change-position-button .btn{box-shadow:none!important;outline:0}.change-position-button label{border-radius:16px}.change-position-button .btn-check:checked+.btn{background-color:var(--smarterplan-primary);color:#fff!important}.filters-menu-block{width:auto}@media (min-width: 1200px){.navbar-brand img{height:100px}.profile_pic{height:60px;width:60px;margin:15px}}@media (min-width: 992px) and (max-width: 1199.98px){.navbar-brand img{height:80px}.profile_pic{height:50px;width:50px;margin:12px}}@media (min-width: 768px) and (max-width: 991.98px){.navbar-brand img{height:60px}.profile_pic{height:40px;width:40px;margin:10px}}@media (max-width: 767.98px){.navbar-brand img{height:50px}.profile_pic{height:30px;width:30px;margin:8px}.search-button-container,.filters-menu-block{width:100%}}.form-container{margin:.5rem 0}.navbar-collapse.show{display:flex;padding-bottom:.5rem}.hidden{width:0;margin:0;border:none;padding:0}.custom-day{text-align:center;padding:.185rem .25rem;display:inline-block;height:2rem;width:2rem}.custom-day.focused{background-color:#e6e6e6}.custom-day.range,.custom-day:hover{background-color:var(--smarterplan-primary-lighter);color:#fff}.custom-day.faded{background-color:var(--smarterplan-primary-transparent)}.calendar{height:100%}.appliedText,.appliedText span{color:var(--smarterplan-primary)}@media (max-width: 767px){.form-inline{flex-direction:column}}.hidden{opacity:0}.date-selector{flex-wrap:nowrap}.date-selector input{min-width:80px;margin:0}@media (min-width: 768px){.w-md-fit-content{width:fit-content!important}.h-md-content{height:fit-content!important}}\n"] }]
|
|
15274
15423
|
}], ctorParameters: () => [{ type: i1$1.Router }, { type: LocaleService }, { type: BaseUserService }, { type: NavigatorService }, { type: SupportService }, { type: BaseVisibilityService }, { type: i1$2.NgbCalendar }, { type: i1$2.NgbDateParserFormatter }, { type: FilterService }, { type: AmplifyCacheService }], propDecorators: { cacheName: [{
|
|
15275
15424
|
type: Input
|
|
15276
15425
|
}] } });
|
|
@@ -15425,27 +15574,27 @@ class BaseTagService {
|
|
|
15425
15574
|
throw new Error('updatePoiMetadata is not implemented in the base class.');
|
|
15426
15575
|
}*/
|
|
15427
15576
|
async prepareEquipmentHtml(equip) {
|
|
15428
|
-
throw new Error(`prepareEquipmentHtml is not implemented in the base class.
|
|
15577
|
+
throw new Error(`prepareEquipmentHtml is not implemented in the base class.
|
|
15429
15578
|
Please override this method in your extended class.`);
|
|
15430
15579
|
}
|
|
15431
15580
|
async prepareTicketHtml(ticket) {
|
|
15432
|
-
throw new Error(`prepareTicketHtml is not implemented in the base class.
|
|
15581
|
+
throw new Error(`prepareTicketHtml is not implemented in the base class.
|
|
15433
15582
|
Please override this method in your extended class.`);
|
|
15434
15583
|
}
|
|
15435
15584
|
async prepareFeatureHtml(feature) {
|
|
15436
|
-
throw new Error(`prepareFeatureHtml is not implemented in the base class.
|
|
15585
|
+
throw new Error(`prepareFeatureHtml is not implemented in the base class.
|
|
15437
15586
|
Please override this method in your extended class.`);
|
|
15438
15587
|
}
|
|
15439
15588
|
async prepareMeasurementHtml(measure) {
|
|
15440
|
-
throw new Error(`prepareMeasurementHtml is not implemented in the base class.
|
|
15589
|
+
throw new Error(`prepareMeasurementHtml is not implemented in the base class.
|
|
15441
15590
|
Please override this method in your extended class.`);
|
|
15442
15591
|
}
|
|
15443
15592
|
async prepareDeskHtml(feature) {
|
|
15444
|
-
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15593
|
+
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15445
15594
|
Please override this method in your extended class.`);
|
|
15446
15595
|
}
|
|
15447
15596
|
async prepareIndicatorHtml(feature) {
|
|
15448
|
-
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15597
|
+
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15449
15598
|
Please override this method in your extended class.`);
|
|
15450
15599
|
}
|
|
15451
15600
|
async getSignedTagIconSource(tagIconSrc) {
|
|
@@ -15454,15 +15603,15 @@ class BaseTagService {
|
|
|
15454
15603
|
getIconTagImageForFeature(feature, poi) {
|
|
15455
15604
|
// const tagIcon = JSON.parse(poi.tagIcon);
|
|
15456
15605
|
// return tagIcon.src;
|
|
15457
|
-
throw new Error(`getIconTagImageForFeature is not implemented in the base class.
|
|
15606
|
+
throw new Error(`getIconTagImageForFeature is not implemented in the base class.
|
|
15458
15607
|
Please override this method in your extended class.`);
|
|
15459
15608
|
}
|
|
15460
15609
|
getScriptForTag(object, tagType) {
|
|
15461
|
-
throw new Error(`getScriptForTag is not implemented in the base class.
|
|
15610
|
+
throw new Error(`getScriptForTag is not implemented in the base class.
|
|
15462
15611
|
Please override this method in your extended class.`);
|
|
15463
15612
|
}
|
|
15464
15613
|
getAnnexeForCommentTypeInFeature(feature, commentType) {
|
|
15465
|
-
throw new Error(`getAnnexeForCommentTypeInFeature is not implemented in the base class.
|
|
15614
|
+
throw new Error(`getAnnexeForCommentTypeInFeature is not implemented in the base class.
|
|
15466
15615
|
Please override this method in your extended class.`);
|
|
15467
15616
|
}
|
|
15468
15617
|
getBillboardMediaToEmbed(object) {
|
|
@@ -15471,27 +15620,27 @@ class BaseTagService {
|
|
|
15471
15620
|
return { comment: null, tagDescription: '' };
|
|
15472
15621
|
}
|
|
15473
15622
|
onActionDetailClick(url) {
|
|
15474
|
-
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15623
|
+
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15475
15624
|
Please override this method in your extended class.`);
|
|
15476
15625
|
}
|
|
15477
15626
|
onActionAudioClick(audioCommentID) {
|
|
15478
|
-
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15627
|
+
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15479
15628
|
Please override this method in your extended class.`);
|
|
15480
15629
|
}
|
|
15481
15630
|
onActionVideoClick(url) {
|
|
15482
|
-
throw new Error(`onActionVideoClick is not implemented in the base class.
|
|
15631
|
+
throw new Error(`onActionVideoClick is not implemented in the base class.
|
|
15483
15632
|
Please override this method in your extended class.`);
|
|
15484
15633
|
}
|
|
15485
15634
|
onActionImageClick(imageCommentID) {
|
|
15486
|
-
throw new Error(`onActionImageClick is not implemented in the base class.
|
|
15635
|
+
throw new Error(`onActionImageClick is not implemented in the base class.
|
|
15487
15636
|
Please override this method in your extended class.`);
|
|
15488
15637
|
}
|
|
15489
15638
|
onActionDocClick(url) {
|
|
15490
|
-
throw new Error(`onActionDocClick is not implemented in the base class.
|
|
15639
|
+
throw new Error(`onActionDocClick is not implemented in the base class.
|
|
15491
15640
|
Please override this method in your extended class.`);
|
|
15492
15641
|
}
|
|
15493
15642
|
onActionYoutubeClick(url) {
|
|
15494
|
-
throw new Error(`onActionYoutubeClick is not implemented in the base class.
|
|
15643
|
+
throw new Error(`onActionYoutubeClick is not implemented in the base class.
|
|
15495
15644
|
Please override this method in your extended class.`);
|
|
15496
15645
|
}
|
|
15497
15646
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseTagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -15599,6 +15748,11 @@ class MatterportImportService {
|
|
|
15599
15748
|
}
|
|
15600
15749
|
async initSdkForModel(modelID) {
|
|
15601
15750
|
this.stop = false;
|
|
15751
|
+
// This service is a singleton: without a reset, the readiness wait below was satisfied at
|
|
15752
|
+
// once by the sweeps/floors of the PREVIOUS import, and the new import ran on stale data.
|
|
15753
|
+
this.sweeps = undefined;
|
|
15754
|
+
this.floors = undefined;
|
|
15755
|
+
this.currentFloor = undefined;
|
|
15602
15756
|
// Load SDK
|
|
15603
15757
|
console.log('Loading Matterport SDK');
|
|
15604
15758
|
this.modelID = modelID;
|
|
@@ -15636,8 +15790,9 @@ class MatterportImportService {
|
|
|
15636
15790
|
}.bind(this),
|
|
15637
15791
|
});
|
|
15638
15792
|
await this.sdk.Settings.update('labels', false);
|
|
15793
|
+
// The showcase can take well over 7 s to publish its sweeps on a slow connection.
|
|
15639
15794
|
let timeoutExpired = false;
|
|
15640
|
-
setTimeout(() => (timeoutExpired = true),
|
|
15795
|
+
setTimeout(() => (timeoutExpired = true), 20000);
|
|
15641
15796
|
await waitUntil(() => (this.sweeps !== undefined && this.floors !== undefined) ||
|
|
15642
15797
|
timeoutExpired === true);
|
|
15643
15798
|
if (timeoutExpired) {
|
|
@@ -15684,7 +15839,8 @@ class MatterportImportService {
|
|
|
15684
15839
|
const layerBuilding = await this.getLayerByName('BUILDING');
|
|
15685
15840
|
const createdDefaultZone = await this.createZone(node.metadata, layerBuilding.id, surface, mainZone.id, Object.keys(this.sweeps), node);
|
|
15686
15841
|
if (!createdDefaultZone) {
|
|
15687
|
-
|
|
15842
|
+
// Nothing else can be imported without this zone: fail loudly instead of "succeeding"
|
|
15843
|
+
return Promise.reject(new Error('the zone of the visit could not be created'));
|
|
15688
15844
|
}
|
|
15689
15845
|
if (this.floors) {
|
|
15690
15846
|
floorZones = await this.importFloorData(createdDefaultZone.id, node);
|
|
@@ -16736,6 +16892,7 @@ class MatterportTagCopyService {
|
|
|
16736
16892
|
operationService;
|
|
16737
16893
|
domainService;
|
|
16738
16894
|
translate;
|
|
16895
|
+
zoneService;
|
|
16739
16896
|
// Emits progress updates during copyTagsFromVisit(); null when idle
|
|
16740
16897
|
copyProgress$ = new BehaviorSubject(null);
|
|
16741
16898
|
// Emits the accumulated log lines during copyTagsFromVisit(); [] when idle
|
|
@@ -16795,7 +16952,7 @@ class MatterportTagCopyService {
|
|
|
16795
16952
|
targetDomainIdsByTypeAndName = new Map();
|
|
16796
16953
|
/** Target space id of the run in progress — used to re-home copied tag icons. */
|
|
16797
16954
|
targetSpaceId = null;
|
|
16798
|
-
constructor(navigationService, userService, poiService, ticketService, equipmentService, object3DService, featureService, measurementService, commentService, hashtagService, missionService, operationService, domainService, translate) {
|
|
16955
|
+
constructor(navigationService, userService, poiService, ticketService, equipmentService, object3DService, featureService, measurementService, commentService, hashtagService, missionService, operationService, domainService, translate, zoneService) {
|
|
16799
16956
|
this.navigationService = navigationService;
|
|
16800
16957
|
this.userService = userService;
|
|
16801
16958
|
this.poiService = poiService;
|
|
@@ -16810,6 +16967,7 @@ class MatterportTagCopyService {
|
|
|
16810
16967
|
this.operationService = operationService;
|
|
16811
16968
|
this.domainService = domainService;
|
|
16812
16969
|
this.translate = translate;
|
|
16970
|
+
this.zoneService = zoneService;
|
|
16813
16971
|
this.spModule = userService.getSpModule();
|
|
16814
16972
|
}
|
|
16815
16973
|
//
|
|
@@ -16818,6 +16976,8 @@ class MatterportTagCopyService {
|
|
|
16818
16976
|
async copyTagsFromVisit(sourceSpaceId, targetSpaceId, landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB) {
|
|
16819
16977
|
let errorCount = 0;
|
|
16820
16978
|
let healedCount = 0;
|
|
16979
|
+
// items skipped because an equivalent already exists in the target (earlier run)
|
|
16980
|
+
let alreadyPresentCount = 0;
|
|
16821
16981
|
this.resetLog();
|
|
16822
16982
|
this.resetRunState(targetSpaceId);
|
|
16823
16983
|
try {
|
|
@@ -16886,8 +17046,9 @@ class MatterportTagCopyService {
|
|
|
16886
17046
|
// loadDomainIndex() for why this is keyed to Mission, not to the Space itself.
|
|
16887
17047
|
await this.loadDomainIndex(sourceSpaceId, targetSpaceId);
|
|
16888
17048
|
if (this.spModule == SpModule.IMMO) {
|
|
16889
|
-
sourceMeasurements = await this.measurementService.getMeasurementsForSpaceForUser(sourceSpaceId)
|
|
16890
|
-
|
|
17049
|
+
sourceMeasurements = (await this.measurementService.getMeasurementsForSpaceForUser(sourceSpaceId))
|
|
17050
|
+
.filter(m => (m.numberPoints ?? 0) > 0);
|
|
17051
|
+
targetMeasurements = (await this.measurementService.getMeasurementsForSpaceForUser(targetSpaceId));
|
|
16891
17052
|
}
|
|
16892
17053
|
this.setStepProgress('collecting', 'collecting', 90);
|
|
16893
17054
|
const sourcePoisAll = await this.poiService.getPoisByMatterportSweeps(sourceSweepIds);
|
|
@@ -16951,6 +17112,9 @@ class MatterportTagCopyService {
|
|
|
16951
17112
|
const sourceObj = sourceTickets[i];
|
|
16952
17113
|
try {
|
|
16953
17114
|
const existingMatch = this.findExisting(sourceObj, targetTickets, (t) => [t.title, t.description]);
|
|
17115
|
+
if (existingMatch) {
|
|
17116
|
+
alreadyPresentCount++;
|
|
17117
|
+
}
|
|
16954
17118
|
if (!existingMatch) {
|
|
16955
17119
|
const rawSource = sourceObj;
|
|
16956
17120
|
const ticketInput = {
|
|
@@ -17070,6 +17234,9 @@ class MatterportTagCopyService {
|
|
|
17070
17234
|
// Equipment has no `title`/`description`: it identifies itself by name, and by
|
|
17071
17235
|
// serial number when one is recorded.
|
|
17072
17236
|
const existingMatch = this.findExisting(sourceObj, targetEquipments, (e) => [e.name, e.serialNumber]);
|
|
17237
|
+
if (existingMatch) {
|
|
17238
|
+
alreadyPresentCount++;
|
|
17239
|
+
}
|
|
17073
17240
|
if (!existingMatch) {
|
|
17074
17241
|
const rawSource = sourceObj;
|
|
17075
17242
|
let copiedPhotoKey = null;
|
|
@@ -17249,6 +17416,9 @@ class MatterportTagCopyService {
|
|
|
17249
17416
|
const sourceObj = sourceObjects3D[i];
|
|
17250
17417
|
try {
|
|
17251
17418
|
const existsInTarget = targetObjects3D.some(targetObj => targetObj.name === sourceObj.name);
|
|
17419
|
+
if (existsInTarget) {
|
|
17420
|
+
alreadyPresentCount++;
|
|
17421
|
+
}
|
|
17252
17422
|
if (!existsInTarget) {
|
|
17253
17423
|
const rawSource = sourceObj;
|
|
17254
17424
|
// `path` means two different things depending on `s3Bucket`, exactly as the
|
|
@@ -17366,6 +17536,9 @@ class MatterportTagCopyService {
|
|
|
17366
17536
|
const sourceObj = sourceFeatures[i];
|
|
17367
17537
|
try {
|
|
17368
17538
|
const existingMatch = this.findExisting(sourceObj, targetFeatures, (f) => [f.title, f.description]);
|
|
17539
|
+
if (existingMatch) {
|
|
17540
|
+
alreadyPresentCount++;
|
|
17541
|
+
}
|
|
17369
17542
|
if (!existingMatch) {
|
|
17370
17543
|
const rawSource = sourceObj;
|
|
17371
17544
|
// Resolved just before the write: a keyword is only created in the target
|
|
@@ -17470,6 +17643,9 @@ class MatterportTagCopyService {
|
|
|
17470
17643
|
const sourceMeasurement = sourceMeasurements[i];
|
|
17471
17644
|
try {
|
|
17472
17645
|
const existsInTarget = targetMeasurements.some(tm => tm.comment.title === sourceMeasurement.comment.title);
|
|
17646
|
+
if (existsInTarget) {
|
|
17647
|
+
alreadyPresentCount++;
|
|
17648
|
+
}
|
|
17473
17649
|
if (!existsInTarget) {
|
|
17474
17650
|
const rawComment = sourceMeasurement.comment;
|
|
17475
17651
|
let copiedAnnexe = null;
|
|
@@ -17529,7 +17705,15 @@ class MatterportTagCopyService {
|
|
|
17529
17705
|
for (let i = 0; i < sourcePois.length; i++) {
|
|
17530
17706
|
const sourcePoi = sourcePois[i];
|
|
17531
17707
|
try {
|
|
17532
|
-
|
|
17708
|
+
// Compared on the parsed position, where the copy WOULD land: the stored strings
|
|
17709
|
+
// differ in format ('{ "x":' vs '{"x":') and, once landmarks move the tags, the
|
|
17710
|
+
// source string never equals its copy's, so every re-run duplicated these POIs.
|
|
17711
|
+
const expectedPosition = this.parseCoordinate(this.getAdjustedPositionOnly(sourcePoi.coordinate, transform));
|
|
17712
|
+
const existsInTarget = targetPois.some(tp => tp.tagDescription === sourcePoi.tagDescription
|
|
17713
|
+
&& this.isSamePosition(this.parseCoordinate(tp.coordinate), expectedPosition));
|
|
17714
|
+
if (existsInTarget) {
|
|
17715
|
+
alreadyPresentCount++;
|
|
17716
|
+
}
|
|
17533
17717
|
if (!existsInTarget) {
|
|
17534
17718
|
const elementID = sourcePoi.elementID
|
|
17535
17719
|
? (elementIds[sourcePoi.elementID] || sourcePoi.elementID)
|
|
@@ -17564,6 +17748,10 @@ class MatterportTagCopyService {
|
|
|
17564
17748
|
if (healedCount > 0) {
|
|
17565
17749
|
this.setStepLog('healedSummary', this.translate.instant('matterportCopy.healedSummary', { count: healedCount }));
|
|
17566
17750
|
}
|
|
17751
|
+
// Says plainly that a re-run created nothing new, instead of a bare "success".
|
|
17752
|
+
if (alreadyPresentCount > 0) {
|
|
17753
|
+
this.setStepLog('alreadyPresentSummary', this.translate.instant('matterportCopy.alreadyPresentSummary', { count: alreadyPresentCount }));
|
|
17754
|
+
}
|
|
17567
17755
|
return true;
|
|
17568
17756
|
}
|
|
17569
17757
|
catch (error) {
|
|
@@ -18320,6 +18508,28 @@ class MatterportTagCopyService {
|
|
|
18320
18508
|
yRotation: applyRigidTransformToYRotationDeg(parsed.yRotation, transform)
|
|
18321
18509
|
};
|
|
18322
18510
|
}
|
|
18511
|
+
/**
|
|
18512
|
+
* Reads a stored coordinate (JSON string or object, whatever its spacing) as a position.
|
|
18513
|
+
* Null for a virtual POI or an unreadable value.
|
|
18514
|
+
*/
|
|
18515
|
+
parseCoordinate(value) {
|
|
18516
|
+
try {
|
|
18517
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
18518
|
+
return parsed && typeof parsed.x === 'number'
|
|
18519
|
+
? { x: parsed.x, y: parsed.y, z: parsed.z }
|
|
18520
|
+
: null;
|
|
18521
|
+
}
|
|
18522
|
+
catch {
|
|
18523
|
+
return null;
|
|
18524
|
+
}
|
|
18525
|
+
}
|
|
18526
|
+
/** Two positions within 1 cm are the same (two virtual POIs, both null, are too). */
|
|
18527
|
+
isSamePosition(a, b, toleranceM = 0.01) {
|
|
18528
|
+
if (!a || !b) {
|
|
18529
|
+
return !a && !b;
|
|
18530
|
+
}
|
|
18531
|
+
return distance(a, b) <= toleranceM;
|
|
18532
|
+
}
|
|
18323
18533
|
/**
|
|
18324
18534
|
* Applies the rigid transform's translation+rotation to a plain {x,y,z} position,
|
|
18325
18535
|
* WITHOUT adding xRotation/yRotation keys. Used for measurements, whose stored
|
|
@@ -18545,13 +18755,403 @@ class MatterportTagCopyService {
|
|
|
18545
18755
|
// for the CopySource header. Do NOT re-encode it here.
|
|
18546
18756
|
return extracted;
|
|
18547
18757
|
}
|
|
18548
|
-
|
|
18758
|
+
/**
|
|
18759
|
+
* Both tag lists a recalibration can offer for a target space, computed in one pass. Only
|
|
18760
|
+
* the target location's own tags are ever listed (see RecalibrationTagScope); tags whose
|
|
18761
|
+
* element was deleted — orphan POIs — never are.
|
|
18762
|
+
* - `space`: every tag of the location, in any of its visits;
|
|
18763
|
+
* - `visit`: the tags of the location sitting on the sweeps of the selected target visit
|
|
18764
|
+
* (`options.targetNodeId`); empty when no visit is given.
|
|
18765
|
+
* With `options.onlyTagsInSource` and a source other than the target, both lists only keep
|
|
18766
|
+
* the tags that also exist in the source location (same identity as the copy's duplicate
|
|
18767
|
+
* detection): typically the tags an earlier copy brought over.
|
|
18768
|
+
*
|
|
18769
|
+
* A POI carries no name of its own: each tag gets `elementName`, the name of the element
|
|
18770
|
+
* it points at (ticket title, equipment name, ...).
|
|
18771
|
+
*/
|
|
18772
|
+
async getRecalibrationTagSets(sourceSpaceId, targetSpaceId, options = {}) {
|
|
18773
|
+
if (!sourceSpaceId || !targetSpaceId) {
|
|
18774
|
+
return { space: [], visit: [] };
|
|
18775
|
+
}
|
|
18776
|
+
const filterBySource = !!options.onlyTagsInSource && sourceSpaceId !== targetSpaceId;
|
|
18777
|
+
const [targetTags, sourceTags] = await Promise.all([
|
|
18778
|
+
this.loadLiveTagsForSpace(targetSpaceId, options.targetNodeId),
|
|
18779
|
+
filterBySource ? this.loadLiveTagsForSpace(sourceSpaceId) : Promise.resolve(null)
|
|
18780
|
+
]);
|
|
18781
|
+
const sourceKeys = sourceTags && new Set(sourceTags.filter(tag => tag.ownedBySpace).map(tag => tag.identity));
|
|
18782
|
+
const ownTargetTags = targetTags
|
|
18783
|
+
.filter(tag => tag.ownedBySpace)
|
|
18784
|
+
.filter(tag => !sourceKeys || sourceKeys.has(tag.identity));
|
|
18785
|
+
return {
|
|
18786
|
+
space: ownTargetTags.map(tag => tag.poi),
|
|
18787
|
+
visit: ownTargetTags.filter(tag => tag.inVisit).map(tag => tag.poi)
|
|
18788
|
+
};
|
|
18789
|
+
}
|
|
18790
|
+
/**
|
|
18791
|
+
* Signed, displayable URL of a tag's picture (`elementImageKey`). Meant to be called on
|
|
18792
|
+
* demand — when the tag is previewed — rather than for the whole list.
|
|
18793
|
+
*/
|
|
18794
|
+
async getTagImageUrl(imageKey) {
|
|
18795
|
+
const key = this.extractS3KeyFromValue(imageKey);
|
|
18796
|
+
return key ? getSignedFile(key) : null;
|
|
18797
|
+
}
|
|
18798
|
+
/**
|
|
18799
|
+
* Loads the POIs placed on the sweeps of a space whose element still exists, each with a
|
|
18800
|
+
* display name, an identity key and whether its element belongs to that space. The key
|
|
18801
|
+
* follows the same rules as the copy's duplicate detection (findExisting), so a tag and its
|
|
18802
|
+
* copy in another space share the same key. With a visit node, `inVisit` tells whether the
|
|
18803
|
+
* tag sits on one of that visit's sweeps.
|
|
18804
|
+
*/
|
|
18805
|
+
async loadLiveTagsForSpace(spaceId, visitNodeId) {
|
|
18806
|
+
const [pois, elements, zones] = await Promise.all([
|
|
18807
|
+
this.navigationService.getAllowedSweepsIDsForUserInSpace(spaceId)
|
|
18808
|
+
.then(sweepIds => this.poiService.getPoisByMatterportSweeps(sweepIds)),
|
|
18809
|
+
this.getTagElementsForSpace(spaceId),
|
|
18810
|
+
this.zoneService.getZonesBySpace(spaceId).catch(error => {
|
|
18811
|
+
console.error('Failed to load the zones of the space:', error);
|
|
18812
|
+
return [];
|
|
18813
|
+
})
|
|
18814
|
+
]);
|
|
18815
|
+
const sweepZones = this.getSweepZones(zones || []);
|
|
18816
|
+
const visitSweeps = visitNodeId ? await this.getSweepsOfVisit(visitNodeId, zones || []) : new Set();
|
|
18817
|
+
// A POI can point at an element stored under another space (left behind by an earlier
|
|
18818
|
+
// copy): those are not in the space-wide lists and are fetched by ID.
|
|
18819
|
+
const unresolved = (pois || []).filter(poi => poi?.elementID && !elements.has(poi.elementID));
|
|
18820
|
+
await this.fetchTagElementsById(unresolved, elements);
|
|
18821
|
+
const result = [];
|
|
18822
|
+
for (const poi of pois || []) {
|
|
18823
|
+
if (!poi) {
|
|
18824
|
+
continue;
|
|
18825
|
+
}
|
|
18826
|
+
let element;
|
|
18827
|
+
if (poi.elementID) {
|
|
18828
|
+
element = elements.get(poi.elementID);
|
|
18829
|
+
if (!element) {
|
|
18830
|
+
continue; // orphan: the element was deleted (or cannot be read)
|
|
18831
|
+
}
|
|
18832
|
+
}
|
|
18833
|
+
else {
|
|
18834
|
+
// standalone tag: its description is all that identifies it
|
|
18835
|
+
const description = this.stripHtml(poi.tagDescription);
|
|
18836
|
+
element = { name: description, identity: [description] };
|
|
18837
|
+
}
|
|
18838
|
+
const zones = sweepZones.get(poi.matterportSweepID);
|
|
18839
|
+
result.push({
|
|
18840
|
+
poi: {
|
|
18841
|
+
...poi,
|
|
18842
|
+
elementName: element.name,
|
|
18843
|
+
elementDescription: element.description,
|
|
18844
|
+
elementImageKey: element.imageKey,
|
|
18845
|
+
floorName: zones?.floor,
|
|
18846
|
+
zoneName: zones?.zone
|
|
18847
|
+
},
|
|
18848
|
+
identity: this.identityKey([poi.type, ...element.identity]),
|
|
18849
|
+
// decided by the element's own spaceID rather than by its presence in the
|
|
18850
|
+
// space-wide lists, some of which are not paginated. A standalone tag has no
|
|
18851
|
+
// element to tell: it belongs to every space that shows it.
|
|
18852
|
+
ownedBySpace: !poi.elementID || element.spaceId === spaceId,
|
|
18853
|
+
inVisit: visitSweeps.has(poi.matterportSweepID)
|
|
18854
|
+
});
|
|
18855
|
+
}
|
|
18856
|
+
return result;
|
|
18857
|
+
}
|
|
18858
|
+
/**
|
|
18859
|
+
* Sweeps of a virtual visit (a Node): those of the space's zones attached to that node,
|
|
18860
|
+
* else — zones not filled in for this visit — the sweeps of the node's navigations.
|
|
18861
|
+
*/
|
|
18862
|
+
async getSweepsOfVisit(nodeId, zones) {
|
|
18863
|
+
const sweeps = new Set(zones
|
|
18864
|
+
.filter(zone => zone.nodeIDs?.includes(nodeId))
|
|
18865
|
+
.flatMap(zone => zone.sweepIDs || []));
|
|
18866
|
+
if (sweeps.size === 0) {
|
|
18867
|
+
try {
|
|
18868
|
+
const navigations = await this.navigationService.getNavigationsForNode(nodeId);
|
|
18869
|
+
navigations.forEach(navigation => navigation.matterportSweepID && sweeps.add(navigation.matterportSweepID));
|
|
18870
|
+
}
|
|
18871
|
+
catch (error) {
|
|
18872
|
+
console.error('Failed to load the sweeps of the visit:', error);
|
|
18873
|
+
}
|
|
18874
|
+
}
|
|
18875
|
+
return sweeps;
|
|
18876
|
+
}
|
|
18877
|
+
/**
|
|
18878
|
+
* Maps each sweep of a space to the names of its floor (zone of layer FLOOR) and of its
|
|
18879
|
+
* most specific other zone (the one holding the fewest sweeps, typically a room, else the
|
|
18880
|
+
* visit's BUILDING zone).
|
|
18881
|
+
*/
|
|
18882
|
+
getSweepZones(zones) {
|
|
18883
|
+
const bySweep = new Map();
|
|
18884
|
+
const isFloor = (zone) => (zone.layer?.name || '').includes('FLOOR');
|
|
18885
|
+
const zoneRank = new Map(); // sweep -> sweep count of the zone kept so far
|
|
18886
|
+
for (const zone of zones) {
|
|
18887
|
+
for (const sweepId of zone.sweepIDs || []) {
|
|
18888
|
+
const entry = bySweep.get(sweepId) || {};
|
|
18889
|
+
if (isFloor(zone)) {
|
|
18890
|
+
entry.floor = entry.floor || zone.name;
|
|
18891
|
+
}
|
|
18892
|
+
else {
|
|
18893
|
+
const size = zone.sweepIDs.length;
|
|
18894
|
+
if (!zoneRank.has(sweepId) || size < zoneRank.get(sweepId)) {
|
|
18895
|
+
zoneRank.set(sweepId, size);
|
|
18896
|
+
entry.zone = zone.name;
|
|
18897
|
+
}
|
|
18898
|
+
}
|
|
18899
|
+
bySweep.set(sweepId, entry);
|
|
18900
|
+
}
|
|
18901
|
+
}
|
|
18902
|
+
return bySweep;
|
|
18903
|
+
}
|
|
18904
|
+
/**
|
|
18905
|
+
* Indexes, by ID, every element of a space a POI can point at. Each list is fetched
|
|
18906
|
+
* independently: one failing (module not enabled, missing permission) must not hide the
|
|
18907
|
+
* others — their POIs are then resolved one by one by fetchTagElementsById().
|
|
18908
|
+
*/
|
|
18909
|
+
async getTagElementsForSpace(spaceId) {
|
|
18910
|
+
const elements = new Map();
|
|
18911
|
+
const [tickets, equipments, objects3D, features, comments] = await Promise.allSettled([
|
|
18912
|
+
this.ticketService.getTicketsBySpace(spaceId),
|
|
18913
|
+
this.equipmentService.getEquipmentsForSpace(spaceId),
|
|
18914
|
+
this.object3DService.getObjects3DBySpace(spaceId),
|
|
18915
|
+
this.featureService.getAllFeaturesBySpaceRaw(spaceId),
|
|
18916
|
+
// a measurement POI is bound to the measurement's Comment, not to the measurement
|
|
18917
|
+
this.commentService.getCommentsBySpaceID(spaceId)
|
|
18918
|
+
]);
|
|
18919
|
+
const index = (settled, type) => {
|
|
18920
|
+
if (settled.status === 'fulfilled') {
|
|
18921
|
+
settled.value?.forEach(item => {
|
|
18922
|
+
if (item?.id) {
|
|
18923
|
+
elements.set(item.id, this.toTagElement(type, { spaceID: spaceId, ...item }));
|
|
18924
|
+
}
|
|
18925
|
+
});
|
|
18926
|
+
}
|
|
18927
|
+
};
|
|
18928
|
+
index(tickets, 'ticket');
|
|
18929
|
+
index(equipments, 'equipment');
|
|
18930
|
+
index(objects3D, 'object3D');
|
|
18931
|
+
index(features, 'feature');
|
|
18932
|
+
index(comments, 'comment');
|
|
18933
|
+
return elements;
|
|
18934
|
+
}
|
|
18935
|
+
/**
|
|
18936
|
+
* Fetches by ID the elements the space-wide lists did not return. The IDs are packed into
|
|
18937
|
+
* a few GraphQL requests using aliases (`e0: getTicket(id: ...) e1: getEquipment(...)`),
|
|
18938
|
+
* instead of one request per element: a space can hold over a thousand orphan POIs.
|
|
18939
|
+
* An element that no longer exists comes back as null and is simply not indexed.
|
|
18940
|
+
*/
|
|
18941
|
+
async fetchTagElementsById(pois, elements) {
|
|
18942
|
+
const IDS_PER_REQUEST = 100;
|
|
18943
|
+
const queries = {
|
|
18944
|
+
ticket: 'getTicket(id: $ID) { id spaceID title description }',
|
|
18945
|
+
equipment: 'getEquipment(id: $ID) { id spaceID name serialNumber }',
|
|
18946
|
+
object3D: 'getObject3D(id: $ID) { id spaceID name description }',
|
|
18947
|
+
comment: 'getComment(id: $ID) { id spaceID title description annexe }',
|
|
18948
|
+
feature: 'getFeature(id: $ID) { id spaceID title description }'
|
|
18949
|
+
};
|
|
18950
|
+
const pending = new Map();
|
|
18951
|
+
for (const poi of pois) {
|
|
18952
|
+
pending.set(poi.elementID, this.tagElementTypeOf(poi.type));
|
|
18953
|
+
}
|
|
18954
|
+
const entries = [...pending.entries()];
|
|
18955
|
+
const batches = [];
|
|
18956
|
+
for (let i = 0; i < entries.length; i += IDS_PER_REQUEST) {
|
|
18957
|
+
batches.push(entries.slice(i, i + IDS_PER_REQUEST));
|
|
18958
|
+
}
|
|
18959
|
+
await Promise.all(batches.map(async (batch) => {
|
|
18960
|
+
const fields = batch.map(([id, type], i) => `e${i}: ${queries[type].replace('$ID', JSON.stringify(id))}`);
|
|
18961
|
+
let data;
|
|
18962
|
+
try {
|
|
18963
|
+
data = (await API.graphql(graphqlOperation(`query TagElements { ${fields.join('\n')} }`))).data;
|
|
18964
|
+
}
|
|
18965
|
+
catch (error) {
|
|
18966
|
+
// Amplify rejects when ANY alias errors (e.g. an unreadable record), but still
|
|
18967
|
+
// hands over the data of the aliases that succeeded.
|
|
18968
|
+
data = error?.data;
|
|
18969
|
+
if (!data) {
|
|
18970
|
+
console.error('Failed to fetch tag elements by ID:', error);
|
|
18971
|
+
return;
|
|
18972
|
+
}
|
|
18973
|
+
}
|
|
18974
|
+
batch.forEach(([id, type], i) => {
|
|
18975
|
+
const item = data[`e${i}`];
|
|
18976
|
+
if (item) {
|
|
18977
|
+
elements.set(id, this.toTagElement(type, item));
|
|
18978
|
+
}
|
|
18979
|
+
});
|
|
18980
|
+
}));
|
|
18981
|
+
}
|
|
18982
|
+
/**
|
|
18983
|
+
* Moves a stored coordinate. Only the position and the horizontal orientation change:
|
|
18984
|
+
* every other key is kept as is. A coordinate often carries the tag's orientation next to
|
|
18985
|
+
* its position ({x, y, z, xRotation, yRotation}); rebuilding it from the position alone
|
|
18986
|
+
* silently erased that orientation.
|
|
18987
|
+
*/
|
|
18988
|
+
getRecalibratedCoordinate(coordinate, transform) {
|
|
18989
|
+
const position = applyRigidTransformToPoint({ x: coordinate.x, y: coordinate.y, z: coordinate.z }, transform);
|
|
18990
|
+
const moved = { ...coordinate, x: position.x, y: position.y, z: position.z };
|
|
18991
|
+
if ('yRotation' in coordinate) {
|
|
18992
|
+
moved.yRotation = applyRigidTransformToYRotationDeg(coordinate.yRotation, transform);
|
|
18993
|
+
}
|
|
18994
|
+
return moved;
|
|
18995
|
+
}
|
|
18996
|
+
/**
|
|
18997
|
+
* Reads POIs by ID, 100 per GraphQL request (aliases). Missing POIs are skipped. Amplify
|
|
18998
|
+
* rejects a request when ANY alias errors, but still hands over the data of the others:
|
|
18999
|
+
* those are kept, so one unreadable POI does not hide the 99 others of its batch.
|
|
19000
|
+
*/
|
|
19001
|
+
async fetchPoisById(ids) {
|
|
19002
|
+
const IDS_PER_REQUEST = 100;
|
|
19003
|
+
const uniqueIds = [...new Set(ids)];
|
|
19004
|
+
const batches = [];
|
|
19005
|
+
for (let i = 0; i < uniqueIds.length; i += IDS_PER_REQUEST) {
|
|
19006
|
+
batches.push(uniqueIds.slice(i, i + IDS_PER_REQUEST));
|
|
19007
|
+
}
|
|
19008
|
+
const results = await Promise.all(batches.map(async (batch) => {
|
|
19009
|
+
const fields = batch.map((id, i) => `p${i}: getPOI(id: ${JSON.stringify(id)}) { id coordinate metadata }`);
|
|
19010
|
+
let data;
|
|
19011
|
+
try {
|
|
19012
|
+
data = (await API.graphql(graphqlOperation(`query SelectedPois { ${fields.join('\n')} }`))).data;
|
|
19013
|
+
}
|
|
19014
|
+
catch (error) {
|
|
19015
|
+
data = error?.data;
|
|
19016
|
+
if (!data) {
|
|
19017
|
+
console.error('Failed to read the selected POIs:', error);
|
|
19018
|
+
return [];
|
|
19019
|
+
}
|
|
19020
|
+
}
|
|
19021
|
+
return batch.map((_, i) => data[`p${i}`]).filter(poi => !!poi);
|
|
19022
|
+
}));
|
|
19023
|
+
return results.flat();
|
|
19024
|
+
}
|
|
19025
|
+
tagElementTypeOf(poiType) {
|
|
19026
|
+
switch (poiType) {
|
|
19027
|
+
case PoiType.TICKET: return 'ticket';
|
|
19028
|
+
case PoiType.EQUIPMENT: return 'equipment';
|
|
19029
|
+
case PoiType.OBJECT3D: return 'object3D';
|
|
19030
|
+
case PoiType.MEASURE: return 'comment';
|
|
19031
|
+
default: return 'feature';
|
|
19032
|
+
}
|
|
19033
|
+
}
|
|
19034
|
+
/** Display name + identity fields of an element, per the copy's duplicate-detection rules. */
|
|
19035
|
+
toTagElement(type, item) {
|
|
19036
|
+
const spaceId = item.spaceID;
|
|
19037
|
+
const text = (value) => this.stripHtml(value) || undefined;
|
|
19038
|
+
switch (type) {
|
|
19039
|
+
case 'equipment':
|
|
19040
|
+
return { name: item.name || '', identity: [item.name, item.serialNumber], spaceId, description: text(item.description) };
|
|
19041
|
+
case 'object3D':
|
|
19042
|
+
return { name: item.name || '', identity: [item.name], spaceId, description: text(item.description) };
|
|
19043
|
+
case 'comment':
|
|
19044
|
+
// A measurement's title is usually empty: its description holds the dimensions and
|
|
19045
|
+
// becomes the name. Its picture is the screenshot taken when it was measured.
|
|
19046
|
+
return {
|
|
19047
|
+
name: item.title || item.description || '',
|
|
19048
|
+
identity: [item.title, item.description],
|
|
19049
|
+
spaceId,
|
|
19050
|
+
description: item.title ? text(item.description) : undefined,
|
|
19051
|
+
imageKey: item.annexe || undefined
|
|
19052
|
+
};
|
|
19053
|
+
default:
|
|
19054
|
+
return { name: item.title || '', identity: [item.title, item.description], spaceId, description: text(item.description) };
|
|
19055
|
+
}
|
|
19056
|
+
}
|
|
19057
|
+
stripHtml(value) {
|
|
19058
|
+
return (value || '').replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
19059
|
+
}
|
|
19060
|
+
/**
|
|
19061
|
+
* Recalibrates a specific list of existing tags in the target space by applying the rigid
|
|
19062
|
+
* transformation calculated from the selected landmark points.
|
|
19063
|
+
*
|
|
19064
|
+
* Each tag is updated on its own: a failing update is logged and counted, it no longer
|
|
19065
|
+
* stops the remaining tags. Progress and log go through copyProgress$ / copyLog$, like a
|
|
19066
|
+
* copy (phase 'recalibrating'). `tagLabels` (tag id -> name) only makes the log readable.
|
|
19067
|
+
*/
|
|
19068
|
+
async recalibrateTagsFromVisit(targetSpaceId, selectedTagIds, landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB, tagLabels = {}) {
|
|
19069
|
+
const result = { updated: 0, skipped: 0, failed: 0 };
|
|
19070
|
+
const uniqueIds = [...new Set(selectedTagIds)];
|
|
19071
|
+
const total = uniqueIds.length;
|
|
19072
|
+
const label = (id) => tagLabels[id] || `#${id.substring(0, 8)}`;
|
|
19073
|
+
let processed = 0;
|
|
19074
|
+
const emitProgress = (phase) => {
|
|
19075
|
+
this.copyProgress$.next({
|
|
19076
|
+
phase,
|
|
19077
|
+
processedInPhase: processed, totalInPhase: total,
|
|
19078
|
+
processedOverall: processed, totalOverall: total,
|
|
19079
|
+
percent: total > 0 ? Math.round((processed / total) * 100) : 100,
|
|
19080
|
+
errorCount: result.failed, healedCount: 0
|
|
19081
|
+
});
|
|
19082
|
+
this.setStepLog('recalibrating', this.translate.instant('matterportCopy.recalibrateStep', { processed, total }));
|
|
19083
|
+
};
|
|
19084
|
+
this.resetLog();
|
|
19085
|
+
emitProgress('recalibrating');
|
|
19086
|
+
try {
|
|
19087
|
+
const transform = computeRigidTransform(landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB);
|
|
19088
|
+
// Re-read only the selected POIs, by ID, so the transform is applied to their current
|
|
19089
|
+
// position — scanning the whole space again for a handful of tags was the slow path.
|
|
19090
|
+
const targetPois = await this.fetchPoisById(uniqueIds);
|
|
19091
|
+
const foundIds = new Set(targetPois.map(poi => poi.id));
|
|
19092
|
+
uniqueIds.filter(id => !foundIds.has(id)).forEach(id => {
|
|
19093
|
+
result.skipped++;
|
|
19094
|
+
processed++;
|
|
19095
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.recalibrateNotFound', { name: label(id) }));
|
|
19096
|
+
});
|
|
19097
|
+
emitProgress('recalibrating');
|
|
19098
|
+
const UPDATES_IN_PARALLEL = 10;
|
|
19099
|
+
for (let i = 0; i < targetPois.length; i += UPDATES_IN_PARALLEL) {
|
|
19100
|
+
await Promise.all(targetPois.slice(i, i + UPDATES_IN_PARALLEL).map(async (poi) => {
|
|
19101
|
+
const id = poi.id;
|
|
19102
|
+
try {
|
|
19103
|
+
let originalCoord = null;
|
|
19104
|
+
try {
|
|
19105
|
+
originalCoord = typeof poi.coordinate === 'string'
|
|
19106
|
+
? JSON.parse(poi.coordinate)
|
|
19107
|
+
: poi.coordinate;
|
|
19108
|
+
}
|
|
19109
|
+
catch {
|
|
19110
|
+
originalCoord = null;
|
|
19111
|
+
}
|
|
19112
|
+
if (!originalCoord || typeof originalCoord.x !== 'number') {
|
|
19113
|
+
// virtual POI or unreadable coordinate: no position to move
|
|
19114
|
+
result.skipped++;
|
|
19115
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.recalibrateSkipped', { name: label(id) }));
|
|
19116
|
+
return;
|
|
19117
|
+
}
|
|
19118
|
+
await this.poiService.updatePoi({
|
|
19119
|
+
id,
|
|
19120
|
+
coordinate: JSON.stringify(this.getRecalibratedCoordinate(originalCoord, transform)),
|
|
19121
|
+
metadata: this.getAdjustedPoiMetadata(poi.metadata, transform)
|
|
19122
|
+
});
|
|
19123
|
+
result.updated++;
|
|
19124
|
+
}
|
|
19125
|
+
catch (error) {
|
|
19126
|
+
result.failed++;
|
|
19127
|
+
console.error(`Failed to recalibrate the tag ${id}:`, error);
|
|
19128
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.recalibrateError', { name: label(id), error: toErrorMessage(error) }));
|
|
19129
|
+
}
|
|
19130
|
+
finally {
|
|
19131
|
+
processed++;
|
|
19132
|
+
emitProgress('recalibrating');
|
|
19133
|
+
}
|
|
19134
|
+
}));
|
|
19135
|
+
}
|
|
19136
|
+
}
|
|
19137
|
+
catch (error) {
|
|
19138
|
+
// transform or reading failure: nothing left can be moved
|
|
19139
|
+
console.error('Erreur lors du recalibrage des tags:', error);
|
|
19140
|
+
result.failed = total - result.updated - result.skipped;
|
|
19141
|
+
processed = total;
|
|
19142
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.errorGeneral', { error: toErrorMessage(error) }));
|
|
19143
|
+
}
|
|
19144
|
+
emitProgress('done');
|
|
19145
|
+
this.setStepLog('done', this.translate.instant('matterportCopy.recalibrateSummary', result));
|
|
19146
|
+
return result;
|
|
19147
|
+
}
|
|
19148
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, deps: [{ token: NavigationService }, { token: BaseUserService }, { token: PoiService }, { token: TicketsService }, { token: EquipmentService }, { token: Object3DService }, { token: FeatureService }, { token: MeasurementService }, { token: CommentService }, { token: HashtagService }, { token: MissionService }, { token: OperationService }, { token: DomainService }, { token: i1.TranslateService }, { token: ZoneService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
18549
19149
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, providedIn: 'root' });
|
|
18550
19150
|
}
|
|
18551
19151
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, decorators: [{
|
|
18552
19152
|
type: Injectable,
|
|
18553
19153
|
args: [{ providedIn: 'root' }]
|
|
18554
|
-
}], ctorParameters: () => [{ type: NavigationService }, { type: BaseUserService }, { type: PoiService }, { type: TicketsService }, { type: EquipmentService }, { type: Object3DService }, { type: FeatureService }, { type: MeasurementService }, { type: CommentService }, { type: HashtagService }, { type: MissionService }, { type: OperationService }, { type: DomainService }, { type: i1.TranslateService }] });
|
|
19154
|
+
}], ctorParameters: () => [{ type: NavigationService }, { type: BaseUserService }, { type: PoiService }, { type: TicketsService }, { type: EquipmentService }, { type: Object3DService }, { type: FeatureService }, { type: MeasurementService }, { type: CommentService }, { type: HashtagService }, { type: MissionService }, { type: OperationService }, { type: DomainService }, { type: i1.TranslateService }, { type: ZoneService }] });
|
|
18555
19155
|
|
|
18556
19156
|
/* eslint-disable class-methods-use-this */
|
|
18557
19157
|
class OrganisationService {
|