@smarterplan/ngx-smarterplan-core 1.4.17 → 1.4.19
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 +18 -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 +87 -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 +814 -193
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
- package/lib/mattertagData.d.ts +4 -0
- package/lib/services/matterport-navigation.service.d.ts +9 -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? }]
|
|
@@ -2551,6 +2572,8 @@ class MatterportNavigationService {
|
|
|
2551
2572
|
currentRooms = [];
|
|
2552
2573
|
/** Sequence number of the floor currently visible in sdk.Floor.current (null = single-floor or unknown). */
|
|
2553
2574
|
currentFloorSequence = null;
|
|
2575
|
+
/** True while a floorplan transition was explicitly requested through action_toolbox_floorplan. */
|
|
2576
|
+
floorplanRequested = false;
|
|
2554
2577
|
// ── Bidirectional sid ↔ uuid lookup maps ──
|
|
2555
2578
|
// sid = short runtime key used by Matterport SDK (collection keys, Sweep.moveTo, Camera.pose.sweep)
|
|
2556
2579
|
// uuid = persistent identifier stored in the database (zone.sweepIDs, poi.matterportSweepID, startSweepID)
|
|
@@ -2617,12 +2640,27 @@ class MatterportNavigationService {
|
|
|
2617
2640
|
console.log('viewer is in transition, cannot go floorplan');
|
|
2618
2641
|
return;
|
|
2619
2642
|
}
|
|
2643
|
+
this.floorplanRequested = true;
|
|
2620
2644
|
try {
|
|
2621
2645
|
await sdk.Mode.moveTo('mode.floorplan');
|
|
2622
2646
|
}
|
|
2623
2647
|
catch (e) {
|
|
2624
2648
|
console.log('cannot go to floorplan', e);
|
|
2625
2649
|
}
|
|
2650
|
+
finally {
|
|
2651
|
+
this.floorplanRequested = false;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
/**
|
|
2655
|
+
* When a dollhouse camera looks straight down, Matterport reports 'mode.floorplan'
|
|
2656
|
+
* (its "peekaboo" corrected mode) although the camera is still in dollhouse.
|
|
2657
|
+
* The native mode buttons are hidden, so such a switch that we did not request
|
|
2658
|
+
* is never a user action and must not be treated as a real mode change.
|
|
2659
|
+
*/
|
|
2660
|
+
isUnrequestedFloorplanSwitch(previousMode, newMode) {
|
|
2661
|
+
return (previousMode === 'mode.dollhouse' &&
|
|
2662
|
+
newMode === 'mode.floorplan' &&
|
|
2663
|
+
!this.floorplanRequested);
|
|
2626
2664
|
}
|
|
2627
2665
|
action_toolbox_inside_view(sdk) {
|
|
2628
2666
|
sdk.Mode.moveTo('mode.inside');
|
|
@@ -2989,11 +3027,11 @@ class MatterportPointerService {
|
|
|
2989
3027
|
}
|
|
2990
3028
|
updateCursorDisplay(poseMatterport) {
|
|
2991
3029
|
if (this.textDisplayCursorPositionPanel && poseMatterport) {
|
|
2992
|
-
this.textDisplayCursorPositionPanel.innerHTML = `position:
|
|
2993
|
-
${pointToString(poseMatterport.position)}\n
|
|
2994
|
-
normal:
|
|
2995
|
-
${pointToString(poseMatterport.normal)}\n
|
|
2996
|
-
floorId:
|
|
3030
|
+
this.textDisplayCursorPositionPanel.innerHTML = `position:
|
|
3031
|
+
${pointToString(poseMatterport.position)}\n
|
|
3032
|
+
normal:
|
|
3033
|
+
${pointToString(poseMatterport.normal)}\n
|
|
3034
|
+
floorId:
|
|
2997
3035
|
${poseMatterport.floorId}`;
|
|
2998
3036
|
if (this.getCursorPositionButton) {
|
|
2999
3037
|
this.getCursorPositionButton.style.display = 'none';
|
|
@@ -3653,6 +3691,13 @@ class MatterportTagService {
|
|
|
3653
3691
|
tagService = null;
|
|
3654
3692
|
tagsCurrentOpacity = new Map();
|
|
3655
3693
|
tagsCurrentEnabled = new Map();
|
|
3694
|
+
/** tagId -> icon name last applied, so an unchanged icon is not re-applied. */
|
|
3695
|
+
tagsCurrentIcon = new Map();
|
|
3696
|
+
/** Ids of the global SDK Tag collection, and the tags waiting to appear in it, see waitForTagInSdk(). */
|
|
3697
|
+
sdkTagIds = new Set();
|
|
3698
|
+
sdkTagWaiters = new Map();
|
|
3699
|
+
sdkTagSubscription = null;
|
|
3700
|
+
sdkTagSubscriptionSdk = null;
|
|
3656
3701
|
/**
|
|
3657
3702
|
* Single layer holding every Smarterplan tag, added to every view of the space so a
|
|
3658
3703
|
* tag stays in place — same sid, same content — when the user switches between the
|
|
@@ -3696,11 +3741,92 @@ class MatterportTagService {
|
|
|
3696
3741
|
* A layer-scoped Tag module only exposes the *replayable* mutations, meant to build
|
|
3697
3742
|
* the layer's own content; applying them to an already-created tag silently does
|
|
3698
3743
|
* nothing — which is what left every pin white instead of carrying its icon. Only
|
|
3699
|
-
* `add` has to go through the layer, see getTagCreationModule().
|
|
3744
|
+
* `add` has to go through the layer, see getTagCreationModule(). The global module
|
|
3745
|
+
* only knows a layer-created pin once it is rendered: see waitForTagInSdk().
|
|
3700
3746
|
*/
|
|
3701
3747
|
getTagModule(sdk, tagId) {
|
|
3702
3748
|
return sdk?.Tag;
|
|
3703
3749
|
}
|
|
3750
|
+
/** Icon name last applied to a tag, if any. */
|
|
3751
|
+
getCachedTagIcon(tagId) {
|
|
3752
|
+
return this.tagsCurrentIcon.get(tagId);
|
|
3753
|
+
}
|
|
3754
|
+
/** Applies an icon to a tag through its own module and remembers it on success. */
|
|
3755
|
+
async editTagIcon(sdk, tagId, iconName) {
|
|
3756
|
+
await this.getTagModule(sdk, tagId).editIcon(tagId, iconName);
|
|
3757
|
+
this.tagsCurrentIcon.set(tagId, iconName);
|
|
3758
|
+
}
|
|
3759
|
+
/**
|
|
3760
|
+
* Resolves once the global SDK Tag collection — the one edits go through — contains the
|
|
3761
|
+
* tag, so edits do not hit a pin that is not rendered yet ("setPinRenderOverrides on a pin
|
|
3762
|
+
* that doesn't exist"). Gives up after `timeoutMs` and resolves anyway; falls back to a
|
|
3763
|
+
* short wait when the collection cannot be observed. One subscription is shared by every
|
|
3764
|
+
* waiting tag: a space loads hundreds of them.
|
|
3765
|
+
*/
|
|
3766
|
+
waitForTagInSdk(sdk, tagId, timeoutMs = 1500) {
|
|
3767
|
+
if (!tagId || !this.observeSdkTags(sdk))
|
|
3768
|
+
return wait(100);
|
|
3769
|
+
if (this.sdkTagIds.has(tagId))
|
|
3770
|
+
return Promise.resolve();
|
|
3771
|
+
return new Promise((resolve) => {
|
|
3772
|
+
const waiters = this.sdkTagWaiters.get(tagId) || [];
|
|
3773
|
+
const timer = setTimeout(() => {
|
|
3774
|
+
const remaining = (this.sdkTagWaiters.get(tagId) || []).filter(waiter => waiter !== done);
|
|
3775
|
+
if (remaining.length)
|
|
3776
|
+
this.sdkTagWaiters.set(tagId, remaining);
|
|
3777
|
+
else
|
|
3778
|
+
this.sdkTagWaiters.delete(tagId);
|
|
3779
|
+
resolve();
|
|
3780
|
+
}, timeoutMs);
|
|
3781
|
+
const done = () => { clearTimeout(timer); resolve(); };
|
|
3782
|
+
waiters.push(done);
|
|
3783
|
+
this.sdkTagWaiters.set(tagId, waiters);
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3786
|
+
/** Keeps sdkTagIds in sync with the global SDK Tag collection; false when it cannot be observed. */
|
|
3787
|
+
observeSdkTags(sdk) {
|
|
3788
|
+
if (this.sdkTagSubscription && this.sdkTagSubscriptionSdk === sdk)
|
|
3789
|
+
return true;
|
|
3790
|
+
const data = sdk?.Tag?.data;
|
|
3791
|
+
if (typeof data?.subscribe !== 'function')
|
|
3792
|
+
return false;
|
|
3793
|
+
this.stopObservingSdkTags();
|
|
3794
|
+
const markPresent = (id) => {
|
|
3795
|
+
this.sdkTagIds.add(id);
|
|
3796
|
+
const waiters = this.sdkTagWaiters.get(id);
|
|
3797
|
+
if (waiters) {
|
|
3798
|
+
this.sdkTagWaiters.delete(id);
|
|
3799
|
+
waiters.forEach(waiter => waiter());
|
|
3800
|
+
}
|
|
3801
|
+
};
|
|
3802
|
+
try {
|
|
3803
|
+
this.sdkTagSubscriptionSdk = sdk;
|
|
3804
|
+
this.sdkTagSubscription = data.subscribe({
|
|
3805
|
+
onAdded: (id) => markPresent(id),
|
|
3806
|
+
onRemoved: (id) => this.sdkTagIds.delete(id),
|
|
3807
|
+
onCollectionUpdated: (collection) => {
|
|
3808
|
+
const ids = typeof collection?.keys === 'function'
|
|
3809
|
+
? Array.from(collection.keys()) : Object.keys(collection || {});
|
|
3810
|
+
this.sdkTagIds = new Set(ids);
|
|
3811
|
+
ids.forEach(id => this.sdkTagWaiters.has(id) && markPresent(id));
|
|
3812
|
+
},
|
|
3813
|
+
});
|
|
3814
|
+
return true;
|
|
3815
|
+
}
|
|
3816
|
+
catch {
|
|
3817
|
+
this.sdkTagSubscriptionSdk = null;
|
|
3818
|
+
return false;
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
stopObservingSdkTags() {
|
|
3822
|
+
try {
|
|
3823
|
+
this.sdkTagSubscription?.cancel?.();
|
|
3824
|
+
}
|
|
3825
|
+
catch { }
|
|
3826
|
+
this.sdkTagSubscription = null;
|
|
3827
|
+
this.sdkTagSubscriptionSdk = null;
|
|
3828
|
+
this.sdkTagIds.clear();
|
|
3829
|
+
}
|
|
3704
3830
|
/**
|
|
3705
3831
|
* Returns the Tag module every new tag must be created through: the shared layer
|
|
3706
3832
|
* when the View API is available, the global sdk.Tag otherwise.
|
|
@@ -3855,7 +3981,7 @@ class MatterportTagService {
|
|
|
3855
3981
|
const [createdSid] = await tagModule.add(...descriptor);
|
|
3856
3982
|
this.mattertagIDs.push(createdSid);
|
|
3857
3983
|
this.dictionnaryTags.set(createdSid, mattertagData);
|
|
3858
|
-
await
|
|
3984
|
+
await this.waitForTagInSdk(sdk, createdSid);
|
|
3859
3985
|
await setTagIconAndOpacity(createdSid, mattertagData);
|
|
3860
3986
|
injectHtmlInTag(mattertagData.getType(), mattertagData.getObject(), createdSid).catch(err => {
|
|
3861
3987
|
if (isDevMode())
|
|
@@ -3976,6 +4102,7 @@ class MatterportTagService {
|
|
|
3976
4102
|
resetVisibilityCache() {
|
|
3977
4103
|
this.tagsCurrentOpacity.clear();
|
|
3978
4104
|
this.tagsCurrentEnabled.clear();
|
|
4105
|
+
this.tagsCurrentIcon.clear();
|
|
3979
4106
|
}
|
|
3980
4107
|
/** Removes a specific tag from the viewer and local dictionaries. */
|
|
3981
4108
|
async deleteMattertagFromId(sdk, mattertagID) {
|
|
@@ -3983,6 +4110,9 @@ class MatterportTagService {
|
|
|
3983
4110
|
if (sdk)
|
|
3984
4111
|
await this.getTagModule(sdk, mattertagID).remove(mattertagID);
|
|
3985
4112
|
this.dictionnaryTags.delete(mattertagID);
|
|
4113
|
+
this.tagsCurrentIcon.delete(mattertagID);
|
|
4114
|
+
this.tagsCurrentOpacity.delete(mattertagID);
|
|
4115
|
+
this.tagsCurrentEnabled.delete(mattertagID);
|
|
3986
4116
|
const index = this.mattertagIDs.indexOf(mattertagID);
|
|
3987
4117
|
if (index > -1)
|
|
3988
4118
|
this.mattertagIDs.splice(index, 1);
|
|
@@ -4044,14 +4174,8 @@ class MatterportTagService {
|
|
|
4044
4174
|
}
|
|
4045
4175
|
mattertagData.setPoi(poi);
|
|
4046
4176
|
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
4177
|
if (createdTagID && sdk) {
|
|
4054
|
-
await
|
|
4178
|
+
await this.waitForTagInSdk(sdk, createdTagID);
|
|
4055
4179
|
await setTagIconAndOpacity(createdTagID, mattertagData);
|
|
4056
4180
|
injectHtmlInTag(tagType, object, createdTagID).catch(err => {
|
|
4057
4181
|
if (isDevMode())
|
|
@@ -4080,6 +4204,7 @@ class MatterportTagService {
|
|
|
4080
4204
|
const tagModule = this.getTagModule(sdk, mattertagID);
|
|
4081
4205
|
await sdk.Asset.registerTexture(iconName, iconPath);
|
|
4082
4206
|
await tagModule.editIcon(mattertagID, iconName);
|
|
4207
|
+
this.tagsCurrentIcon.set(mattertagID, iconName);
|
|
4083
4208
|
if (applyOpacity) {
|
|
4084
4209
|
await tagModule.editOpacity(mattertagID, opacity);
|
|
4085
4210
|
}
|
|
@@ -4209,6 +4334,8 @@ class MatterportTagService {
|
|
|
4209
4334
|
this.dictionnaryTags.clear();
|
|
4210
4335
|
this.tagsCurrentOpacity.clear();
|
|
4211
4336
|
this.tagsCurrentEnabled.clear();
|
|
4337
|
+
this.tagsCurrentIcon.clear();
|
|
4338
|
+
this.stopObservingSdkTags();
|
|
4212
4339
|
this.tagAddQueue = Promise.resolve();
|
|
4213
4340
|
this.mattertagToFollow = null;
|
|
4214
4341
|
this.mattertagIDs = [];
|
|
@@ -4332,6 +4459,12 @@ class MatterportService {
|
|
|
4332
4459
|
tagAction = new Subject();
|
|
4333
4460
|
/** Views (furnished, defurnished...) exposed by the SDK for the current space. */
|
|
4334
4461
|
viewsByType = new Map();
|
|
4462
|
+
/** Settles once every static icon texture has been registered (or failed). */
|
|
4463
|
+
iconsRegistered = Promise.resolve();
|
|
4464
|
+
/** Names of the textures successfully registered in the current SDK session. */
|
|
4465
|
+
registeredIcons = new Set();
|
|
4466
|
+
/** tagId -> signed source last registered as a custom texture, and its texture name. */
|
|
4467
|
+
customIconCache = new Map();
|
|
4335
4468
|
currentView = null;
|
|
4336
4469
|
viewSubscriptions = [];
|
|
4337
4470
|
/** Emits the active view every time the user switches between furnished/defurnished. */
|
|
@@ -4460,13 +4593,16 @@ class MatterportService {
|
|
|
4460
4593
|
this.addCustomCss();
|
|
4461
4594
|
this.pointerService.startAdminCursorTracker(this.sdk, this.container, () => this.poseMatterport, () => this.poseCamera);
|
|
4462
4595
|
// Load Mattertag icons and custom subscriptions
|
|
4596
|
+
this.registeredIcons.clear();
|
|
4597
|
+
this.customIconCache.clear();
|
|
4598
|
+
const iconRegistrations = [];
|
|
4463
4599
|
switch (module) {
|
|
4464
4600
|
case SpModule.IMMO:
|
|
4465
|
-
this.
|
|
4466
|
-
this.
|
|
4467
|
-
this.
|
|
4468
|
-
this.
|
|
4469
|
-
this.
|
|
4601
|
+
iconRegistrations.push(this.registerIcon('icon-ticket', this.config.my_config.icon_ticket));
|
|
4602
|
+
iconRegistrations.push(this.registerIcon('icon-equipment', this.config.my_config.icon_equipment));
|
|
4603
|
+
iconRegistrations.push(this.registerIcon('icon-measure', this.config.my_config.icon_measure));
|
|
4604
|
+
iconRegistrations.push(this.registerIcon('icon-data', this.config.my_config.icon_data));
|
|
4605
|
+
iconRegistrations.push(this.registerIcon('icon-object3d', this.config.my_config.icon_object3d));
|
|
4470
4606
|
this.sdk.Measurements.data.subscribe({
|
|
4471
4607
|
onAdded: function (index, item, collection) {
|
|
4472
4608
|
this.measurementService.setLastMeasure(item.points);
|
|
@@ -4483,20 +4619,19 @@ class MatterportService {
|
|
|
4483
4619
|
}.bind(this));
|
|
4484
4620
|
break;
|
|
4485
4621
|
case SpModule.MUSEUM:
|
|
4486
|
-
this.
|
|
4622
|
+
iconRegistrations.push(this.registerIcon('icon-data', this.config.my_config.icon_data));
|
|
4487
4623
|
break;
|
|
4488
4624
|
case SpModule.HOTEL:
|
|
4489
|
-
this.
|
|
4490
|
-
this.
|
|
4491
|
-
this.
|
|
4492
|
-
this.
|
|
4625
|
+
iconRegistrations.push(this.registerIcon('icon_room_available', this.config.my_config.icon_room_available));
|
|
4626
|
+
iconRegistrations.push(this.registerIcon('icon_room_unavailable', this.config.my_config.icon_room_unavailable));
|
|
4627
|
+
iconRegistrations.push(this.registerIcon('icon_room_chosen', this.config.my_config.icon_room_chosen));
|
|
4628
|
+
iconRegistrations.push(this.registerIcon('icon_room_viewed', this.config.my_config.icon_room_viewed));
|
|
4493
4629
|
break;
|
|
4494
4630
|
default:
|
|
4495
4631
|
break;
|
|
4496
4632
|
}
|
|
4497
|
-
this.
|
|
4498
|
-
|
|
4499
|
-
console.warn('icon-position texture registration failed', e); });
|
|
4633
|
+
iconRegistrations.push(this.registerIcon('icon-position', this.config.my_config.icon_position));
|
|
4634
|
+
this.iconsRegistered = Promise.allSettled(iconRegistrations).then(() => undefined);
|
|
4500
4635
|
// Current Room (used for getting bounding box and eventually lazy load mattertag or object3D inside current Room)
|
|
4501
4636
|
this.sdk.Room.current.subscribe((currentRoom) => {
|
|
4502
4637
|
const rooms = Array.isArray(currentRoom) ? currentRoom : (currentRoom ? [currentRoom] : []);
|
|
@@ -4527,6 +4662,10 @@ class MatterportService {
|
|
|
4527
4662
|
}.bind(this));
|
|
4528
4663
|
//Camera mode
|
|
4529
4664
|
this.sdk.Mode.current.subscribe((mode) => {
|
|
4665
|
+
if (this.navigationService.isUnrequestedFloorplanSwitch(this.cameraMode, mode)) {
|
|
4666
|
+
// Top-down dollhouse camera reported as floorplan: still dollhouse, ignore it
|
|
4667
|
+
return;
|
|
4668
|
+
}
|
|
4530
4669
|
if (this.cameraMode !== mode) {
|
|
4531
4670
|
this.navigationService.setCameraMode(mode);
|
|
4532
4671
|
// Refresh tag visibility on every mode change (INSIDE vs DOLLHOUSE vs FLOORPLAN)
|
|
@@ -4854,15 +4993,29 @@ class MatterportService {
|
|
|
4854
4993
|
/** Applies a pre-registered icon to a Mattertag. */
|
|
4855
4994
|
async setRegistredIconForTag(mattertagID, iconName) {
|
|
4856
4995
|
try {
|
|
4857
|
-
this.matterportTagService.
|
|
4996
|
+
await this.matterportTagService.editTagIcon(this.sdk, mattertagID, iconName);
|
|
4858
4997
|
}
|
|
4859
4998
|
catch (e) {
|
|
4860
4999
|
if (isDevMode())
|
|
4861
5000
|
console.warn('Could not edit icon', iconName, e);
|
|
4862
5001
|
}
|
|
4863
5002
|
}
|
|
4864
|
-
/**
|
|
5003
|
+
/** Registers a static texture and remembers its name once the SDK accepted it. */
|
|
5004
|
+
async registerIcon(iconName, iconPath) {
|
|
5005
|
+
if (!iconPath)
|
|
5006
|
+
return;
|
|
5007
|
+
try {
|
|
5008
|
+
await this.sdk.Asset.registerTexture(iconName, iconPath);
|
|
5009
|
+
this.registeredIcons.add(iconName);
|
|
5010
|
+
}
|
|
5011
|
+
catch (e) {
|
|
5012
|
+
if (isDevMode())
|
|
5013
|
+
console.warn(`[MatterportService] ${iconName} texture registration failed`, e);
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
/** Sets the appropriate icon for a tag based on its type and POI metadata. */
|
|
4865
5017
|
async setTagIconAndOpacity(mattertagID, mattertagData) {
|
|
5018
|
+
await this.iconsRegistered;
|
|
4866
5019
|
if (this.SPModule === SpModule.HOTEL) {
|
|
4867
5020
|
const room = mattertagData.getObject();
|
|
4868
5021
|
let iconName = `icon_room`;
|
|
@@ -4876,7 +5029,6 @@ class MatterportService {
|
|
|
4876
5029
|
return;
|
|
4877
5030
|
}
|
|
4878
5031
|
const stringTagType = poiTypeToString(mattertagData.getType());
|
|
4879
|
-
let opacity = this.config.my_config.DEFAULT_OPACITY_TAG;
|
|
4880
5032
|
let iconName = `icon-${stringTagType}`;
|
|
4881
5033
|
const poi = mattertagData.getPoi();
|
|
4882
5034
|
if (poi && poi.tagIcon) {
|
|
@@ -4888,31 +5040,45 @@ class MatterportService {
|
|
|
4888
5040
|
}
|
|
4889
5041
|
}
|
|
4890
5042
|
if (tagIcon.src) {
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
5043
|
+
// keyed on the stored source, not on the signed URL: a new signature every call
|
|
5044
|
+
const cached = this.customIconCache.get(mattertagID);
|
|
5045
|
+
if (cached && cached.src === tagIcon.src) {
|
|
5046
|
+
iconName = cached.iconName;
|
|
5047
|
+
}
|
|
5048
|
+
else {
|
|
5049
|
+
const pathSigned = await this.tagService.getSignedTagIconSource(tagIcon.src);
|
|
5050
|
+
if (pathSigned) {
|
|
5051
|
+
try {
|
|
5052
|
+
const customIconName = `icon-${stringTagType}-${mattertagID}-${mattertagData.customIconIndex}`;
|
|
5053
|
+
await this.sdk.Asset.registerTexture(customIconName, pathSigned);
|
|
5054
|
+
mattertagData.customIconIndex += 1;
|
|
5055
|
+
this.customIconCache.set(mattertagID, { src: tagIcon.src, iconName: customIconName });
|
|
5056
|
+
this.registeredIcons.add(customIconName);
|
|
5057
|
+
iconName = customIconName;
|
|
5058
|
+
}
|
|
5059
|
+
catch {
|
|
5060
|
+
console.log('error registerIcon');
|
|
5061
|
+
}
|
|
4900
5062
|
}
|
|
4901
5063
|
}
|
|
4902
5064
|
}
|
|
4903
|
-
if (tagIcon.opacity) {
|
|
4904
|
-
opacity = tagIcon.opacity;
|
|
4905
|
-
}
|
|
4906
5065
|
}
|
|
4907
5066
|
await this.editTagIcon(mattertagID, iconName);
|
|
4908
5067
|
}
|
|
4909
5068
|
/**
|
|
4910
|
-
* Applies an icon to a tag
|
|
4911
|
-
* silently dropped promise here leaves the pin
|
|
5069
|
+
* Applies an icon to a tag, unless that icon is already the one applied. The call is
|
|
5070
|
+
* awaited and its rejection reported: a silently dropped promise here leaves the pin
|
|
5071
|
+
* with its default white look.
|
|
4912
5072
|
*/
|
|
4913
5073
|
async editTagIcon(mattertagID, iconName) {
|
|
5074
|
+
if (this.matterportTagService.getCachedTagIcon(mattertagID) === iconName)
|
|
5075
|
+
return;
|
|
5076
|
+
// A texture that was never registered (no icon configured for this type) can only fail:
|
|
5077
|
+
// the pin keeps its default look, as before, without a doomed SDK call.
|
|
5078
|
+
if (!this.registeredIcons.has(iconName))
|
|
5079
|
+
return;
|
|
4914
5080
|
try {
|
|
4915
|
-
await this.matterportTagService.
|
|
5081
|
+
await this.matterportTagService.editTagIcon(this.sdk, mattertagID, iconName);
|
|
4916
5082
|
}
|
|
4917
5083
|
catch (error) {
|
|
4918
5084
|
if (isDevMode())
|
|
@@ -5015,22 +5181,22 @@ class MatterportService {
|
|
|
5015
5181
|
);
|
|
5016
5182
|
}*/
|
|
5017
5183
|
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
|
-
}
|
|
5184
|
+
const css = `
|
|
5185
|
+
.footer-ui,
|
|
5186
|
+
.showcase-footer,
|
|
5187
|
+
.mp-nova-btn-group,
|
|
5188
|
+
.footer-divider,
|
|
5189
|
+
.logo-link,
|
|
5190
|
+
.footer-logo,
|
|
5191
|
+
.bottom-ui,
|
|
5192
|
+
img.logo-image,
|
|
5193
|
+
img[class^="logo-image"],
|
|
5194
|
+
img[class*=" logo-image"],
|
|
5195
|
+
[data-testid="showcase-footer"] {
|
|
5196
|
+
opacity: 0 !important;
|
|
5197
|
+
visibility: hidden !important;
|
|
5198
|
+
pointer-events: none !important;
|
|
5199
|
+
}
|
|
5034
5200
|
`;
|
|
5035
5201
|
// 1st method: Via Scene SDK
|
|
5036
5202
|
if (this.sdk?.Scene?.addStyle) {
|
|
@@ -8046,11 +8212,11 @@ class ModalSwitchVisitComponent {
|
|
|
8046
8212
|
});
|
|
8047
8213
|
}
|
|
8048
8214
|
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" }] });
|
|
8215
|
+
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
8216
|
}
|
|
8051
8217
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ModalSwitchVisitComponent, decorators: [{
|
|
8052
8218
|
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"] }]
|
|
8219
|
+
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
8220
|
}], ctorParameters: () => [{ type: i1$2.NgbActiveModal }, { type: i1$1.Router }, { type: ViewerService }], propDecorators: { content: [{
|
|
8055
8221
|
type: Input
|
|
8056
8222
|
}], model3D: [{
|
|
@@ -8587,14 +8753,18 @@ class ZoneService {
|
|
|
8587
8753
|
async getZonesBySpace(spaceID) {
|
|
8588
8754
|
const list = [];
|
|
8589
8755
|
if (this.API.__proto__.hasOwnProperty('ZonesBySpace')) {
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8756
|
+
// Paginated: without a nextToken loop, only the first page (100 zones) was returned and
|
|
8757
|
+
// the sweeps of the other zones silently disappeared.
|
|
8758
|
+
let nextToken = null;
|
|
8759
|
+
do {
|
|
8760
|
+
const zones = await this.API.__proto__.ZonesBySpace(spaceID, null, null, 1000, nextToken);
|
|
8761
|
+
for (const zone of zones?.items || []) {
|
|
8593
8762
|
const zoneObject = { ...zone };
|
|
8594
8763
|
zoneObject.virtual = this.zoneIsVirtual(zone);
|
|
8595
8764
|
list.push(zoneObject);
|
|
8596
8765
|
}
|
|
8597
|
-
|
|
8766
|
+
nextToken = zones?.nextToken ?? null;
|
|
8767
|
+
} while (nextToken);
|
|
8598
8768
|
return list;
|
|
8599
8769
|
}
|
|
8600
8770
|
else {
|
|
@@ -13064,11 +13234,11 @@ class SearchBarComponent {
|
|
|
13064
13234
|
this.searchEvent.emit(results);
|
|
13065
13235
|
}
|
|
13066
13236
|
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" }] });
|
|
13237
|
+
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
13238
|
}
|
|
13069
13239
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SearchBarComponent, decorators: [{
|
|
13070
13240
|
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"] }]
|
|
13241
|
+
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
13242
|
}], ctorParameters: () => [{ type: SearchService }], propDecorators: { searchable: [{
|
|
13073
13243
|
type: Input
|
|
13074
13244
|
}], objectType: [{
|
|
@@ -13516,11 +13686,11 @@ class LoaderComponent {
|
|
|
13516
13686
|
document.documentElement.style.setProperty('--color', this.color);
|
|
13517
13687
|
}
|
|
13518
13688
|
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"] }] });
|
|
13689
|
+
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
13690
|
}
|
|
13521
13691
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LoaderComponent, decorators: [{
|
|
13522
13692
|
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"] }]
|
|
13693
|
+
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
13694
|
}], ctorParameters: () => [], propDecorators: { useLogo: [{
|
|
13525
13695
|
type: Input
|
|
13526
13696
|
}], color: [{
|
|
@@ -13578,11 +13748,11 @@ class SupportModalComponent {
|
|
|
13578
13748
|
}
|
|
13579
13749
|
}
|
|
13580
13750
|
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" }] });
|
|
13751
|
+
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
13752
|
}
|
|
13583
13753
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SupportModalComponent, decorators: [{
|
|
13584
13754
|
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"] }]
|
|
13755
|
+
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
13756
|
}], ctorParameters: () => [{ type: SupportService }, { type: i1$2.NgbActiveModal }, { type: i3.UntypedFormBuilder }, { type: BaseUserService }, { type: ValidatorsService }] });
|
|
13587
13757
|
|
|
13588
13758
|
class LocaleService {
|
|
@@ -14993,11 +15163,11 @@ class NavigationBarComponent {
|
|
|
14993
15163
|
this.baseVisibilityService.isChangePositionVisible.next(false);
|
|
14994
15164
|
}
|
|
14995
15165
|
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" }] });
|
|
15166
|
+
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
15167
|
}
|
|
14998
15168
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NavigationBarComponent, decorators: [{
|
|
14999
15169
|
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"] }]
|
|
15170
|
+
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
15171
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
15002
15172
|
type: Inject,
|
|
15003
15173
|
args: ['currentAwsKinesisAnalyticsService']
|
|
@@ -15266,11 +15436,11 @@ class MenuBarComponent {
|
|
|
15266
15436
|
}
|
|
15267
15437
|
}
|
|
15268
15438
|
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" }] });
|
|
15439
|
+
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
15440
|
}
|
|
15271
15441
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MenuBarComponent, decorators: [{
|
|
15272
15442
|
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"] }]
|
|
15443
|
+
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
15444
|
}], 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
15445
|
type: Input
|
|
15276
15446
|
}] } });
|
|
@@ -15425,27 +15595,27 @@ class BaseTagService {
|
|
|
15425
15595
|
throw new Error('updatePoiMetadata is not implemented in the base class.');
|
|
15426
15596
|
}*/
|
|
15427
15597
|
async prepareEquipmentHtml(equip) {
|
|
15428
|
-
throw new Error(`prepareEquipmentHtml is not implemented in the base class.
|
|
15598
|
+
throw new Error(`prepareEquipmentHtml is not implemented in the base class.
|
|
15429
15599
|
Please override this method in your extended class.`);
|
|
15430
15600
|
}
|
|
15431
15601
|
async prepareTicketHtml(ticket) {
|
|
15432
|
-
throw new Error(`prepareTicketHtml is not implemented in the base class.
|
|
15602
|
+
throw new Error(`prepareTicketHtml is not implemented in the base class.
|
|
15433
15603
|
Please override this method in your extended class.`);
|
|
15434
15604
|
}
|
|
15435
15605
|
async prepareFeatureHtml(feature) {
|
|
15436
|
-
throw new Error(`prepareFeatureHtml is not implemented in the base class.
|
|
15606
|
+
throw new Error(`prepareFeatureHtml is not implemented in the base class.
|
|
15437
15607
|
Please override this method in your extended class.`);
|
|
15438
15608
|
}
|
|
15439
15609
|
async prepareMeasurementHtml(measure) {
|
|
15440
|
-
throw new Error(`prepareMeasurementHtml is not implemented in the base class.
|
|
15610
|
+
throw new Error(`prepareMeasurementHtml is not implemented in the base class.
|
|
15441
15611
|
Please override this method in your extended class.`);
|
|
15442
15612
|
}
|
|
15443
15613
|
async prepareDeskHtml(feature) {
|
|
15444
|
-
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15614
|
+
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15445
15615
|
Please override this method in your extended class.`);
|
|
15446
15616
|
}
|
|
15447
15617
|
async prepareIndicatorHtml(feature) {
|
|
15448
|
-
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15618
|
+
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
15449
15619
|
Please override this method in your extended class.`);
|
|
15450
15620
|
}
|
|
15451
15621
|
async getSignedTagIconSource(tagIconSrc) {
|
|
@@ -15454,15 +15624,15 @@ class BaseTagService {
|
|
|
15454
15624
|
getIconTagImageForFeature(feature, poi) {
|
|
15455
15625
|
// const tagIcon = JSON.parse(poi.tagIcon);
|
|
15456
15626
|
// return tagIcon.src;
|
|
15457
|
-
throw new Error(`getIconTagImageForFeature is not implemented in the base class.
|
|
15627
|
+
throw new Error(`getIconTagImageForFeature is not implemented in the base class.
|
|
15458
15628
|
Please override this method in your extended class.`);
|
|
15459
15629
|
}
|
|
15460
15630
|
getScriptForTag(object, tagType) {
|
|
15461
|
-
throw new Error(`getScriptForTag is not implemented in the base class.
|
|
15631
|
+
throw new Error(`getScriptForTag is not implemented in the base class.
|
|
15462
15632
|
Please override this method in your extended class.`);
|
|
15463
15633
|
}
|
|
15464
15634
|
getAnnexeForCommentTypeInFeature(feature, commentType) {
|
|
15465
|
-
throw new Error(`getAnnexeForCommentTypeInFeature is not implemented in the base class.
|
|
15635
|
+
throw new Error(`getAnnexeForCommentTypeInFeature is not implemented in the base class.
|
|
15466
15636
|
Please override this method in your extended class.`);
|
|
15467
15637
|
}
|
|
15468
15638
|
getBillboardMediaToEmbed(object) {
|
|
@@ -15471,27 +15641,27 @@ class BaseTagService {
|
|
|
15471
15641
|
return { comment: null, tagDescription: '' };
|
|
15472
15642
|
}
|
|
15473
15643
|
onActionDetailClick(url) {
|
|
15474
|
-
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15644
|
+
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15475
15645
|
Please override this method in your extended class.`);
|
|
15476
15646
|
}
|
|
15477
15647
|
onActionAudioClick(audioCommentID) {
|
|
15478
|
-
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15648
|
+
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
15479
15649
|
Please override this method in your extended class.`);
|
|
15480
15650
|
}
|
|
15481
15651
|
onActionVideoClick(url) {
|
|
15482
|
-
throw new Error(`onActionVideoClick is not implemented in the base class.
|
|
15652
|
+
throw new Error(`onActionVideoClick is not implemented in the base class.
|
|
15483
15653
|
Please override this method in your extended class.`);
|
|
15484
15654
|
}
|
|
15485
15655
|
onActionImageClick(imageCommentID) {
|
|
15486
|
-
throw new Error(`onActionImageClick is not implemented in the base class.
|
|
15656
|
+
throw new Error(`onActionImageClick is not implemented in the base class.
|
|
15487
15657
|
Please override this method in your extended class.`);
|
|
15488
15658
|
}
|
|
15489
15659
|
onActionDocClick(url) {
|
|
15490
|
-
throw new Error(`onActionDocClick is not implemented in the base class.
|
|
15660
|
+
throw new Error(`onActionDocClick is not implemented in the base class.
|
|
15491
15661
|
Please override this method in your extended class.`);
|
|
15492
15662
|
}
|
|
15493
15663
|
onActionYoutubeClick(url) {
|
|
15494
|
-
throw new Error(`onActionYoutubeClick is not implemented in the base class.
|
|
15664
|
+
throw new Error(`onActionYoutubeClick is not implemented in the base class.
|
|
15495
15665
|
Please override this method in your extended class.`);
|
|
15496
15666
|
}
|
|
15497
15667
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseTagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -15599,6 +15769,11 @@ class MatterportImportService {
|
|
|
15599
15769
|
}
|
|
15600
15770
|
async initSdkForModel(modelID) {
|
|
15601
15771
|
this.stop = false;
|
|
15772
|
+
// This service is a singleton: without a reset, the readiness wait below was satisfied at
|
|
15773
|
+
// once by the sweeps/floors of the PREVIOUS import, and the new import ran on stale data.
|
|
15774
|
+
this.sweeps = undefined;
|
|
15775
|
+
this.floors = undefined;
|
|
15776
|
+
this.currentFloor = undefined;
|
|
15602
15777
|
// Load SDK
|
|
15603
15778
|
console.log('Loading Matterport SDK');
|
|
15604
15779
|
this.modelID = modelID;
|
|
@@ -15636,8 +15811,9 @@ class MatterportImportService {
|
|
|
15636
15811
|
}.bind(this),
|
|
15637
15812
|
});
|
|
15638
15813
|
await this.sdk.Settings.update('labels', false);
|
|
15814
|
+
// The showcase can take well over 7 s to publish its sweeps on a slow connection.
|
|
15639
15815
|
let timeoutExpired = false;
|
|
15640
|
-
setTimeout(() => (timeoutExpired = true),
|
|
15816
|
+
setTimeout(() => (timeoutExpired = true), 20000);
|
|
15641
15817
|
await waitUntil(() => (this.sweeps !== undefined && this.floors !== undefined) ||
|
|
15642
15818
|
timeoutExpired === true);
|
|
15643
15819
|
if (timeoutExpired) {
|
|
@@ -15684,7 +15860,8 @@ class MatterportImportService {
|
|
|
15684
15860
|
const layerBuilding = await this.getLayerByName('BUILDING');
|
|
15685
15861
|
const createdDefaultZone = await this.createZone(node.metadata, layerBuilding.id, surface, mainZone.id, Object.keys(this.sweeps), node);
|
|
15686
15862
|
if (!createdDefaultZone) {
|
|
15687
|
-
|
|
15863
|
+
// Nothing else can be imported without this zone: fail loudly instead of "succeeding"
|
|
15864
|
+
return Promise.reject(new Error('the zone of the visit could not be created'));
|
|
15688
15865
|
}
|
|
15689
15866
|
if (this.floors) {
|
|
15690
15867
|
floorZones = await this.importFloorData(createdDefaultZone.id, node);
|
|
@@ -16736,6 +16913,7 @@ class MatterportTagCopyService {
|
|
|
16736
16913
|
operationService;
|
|
16737
16914
|
domainService;
|
|
16738
16915
|
translate;
|
|
16916
|
+
zoneService;
|
|
16739
16917
|
// Emits progress updates during copyTagsFromVisit(); null when idle
|
|
16740
16918
|
copyProgress$ = new BehaviorSubject(null);
|
|
16741
16919
|
// Emits the accumulated log lines during copyTagsFromVisit(); [] when idle
|
|
@@ -16795,7 +16973,7 @@ class MatterportTagCopyService {
|
|
|
16795
16973
|
targetDomainIdsByTypeAndName = new Map();
|
|
16796
16974
|
/** Target space id of the run in progress — used to re-home copied tag icons. */
|
|
16797
16975
|
targetSpaceId = null;
|
|
16798
|
-
constructor(navigationService, userService, poiService, ticketService, equipmentService, object3DService, featureService, measurementService, commentService, hashtagService, missionService, operationService, domainService, translate) {
|
|
16976
|
+
constructor(navigationService, userService, poiService, ticketService, equipmentService, object3DService, featureService, measurementService, commentService, hashtagService, missionService, operationService, domainService, translate, zoneService) {
|
|
16799
16977
|
this.navigationService = navigationService;
|
|
16800
16978
|
this.userService = userService;
|
|
16801
16979
|
this.poiService = poiService;
|
|
@@ -16810,6 +16988,7 @@ class MatterportTagCopyService {
|
|
|
16810
16988
|
this.operationService = operationService;
|
|
16811
16989
|
this.domainService = domainService;
|
|
16812
16990
|
this.translate = translate;
|
|
16991
|
+
this.zoneService = zoneService;
|
|
16813
16992
|
this.spModule = userService.getSpModule();
|
|
16814
16993
|
}
|
|
16815
16994
|
//
|
|
@@ -16818,6 +16997,8 @@ class MatterportTagCopyService {
|
|
|
16818
16997
|
async copyTagsFromVisit(sourceSpaceId, targetSpaceId, landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB) {
|
|
16819
16998
|
let errorCount = 0;
|
|
16820
16999
|
let healedCount = 0;
|
|
17000
|
+
// items skipped because an equivalent already exists in the target (earlier run)
|
|
17001
|
+
let alreadyPresentCount = 0;
|
|
16821
17002
|
this.resetLog();
|
|
16822
17003
|
this.resetRunState(targetSpaceId);
|
|
16823
17004
|
try {
|
|
@@ -16886,8 +17067,9 @@ class MatterportTagCopyService {
|
|
|
16886
17067
|
// loadDomainIndex() for why this is keyed to Mission, not to the Space itself.
|
|
16887
17068
|
await this.loadDomainIndex(sourceSpaceId, targetSpaceId);
|
|
16888
17069
|
if (this.spModule == SpModule.IMMO) {
|
|
16889
|
-
sourceMeasurements = await this.measurementService.getMeasurementsForSpaceForUser(sourceSpaceId)
|
|
16890
|
-
|
|
17070
|
+
sourceMeasurements = (await this.measurementService.getMeasurementsForSpaceForUser(sourceSpaceId))
|
|
17071
|
+
.filter(m => (m.numberPoints ?? 0) > 0);
|
|
17072
|
+
targetMeasurements = (await this.measurementService.getMeasurementsForSpaceForUser(targetSpaceId));
|
|
16891
17073
|
}
|
|
16892
17074
|
this.setStepProgress('collecting', 'collecting', 90);
|
|
16893
17075
|
const sourcePoisAll = await this.poiService.getPoisByMatterportSweeps(sourceSweepIds);
|
|
@@ -16951,6 +17133,9 @@ class MatterportTagCopyService {
|
|
|
16951
17133
|
const sourceObj = sourceTickets[i];
|
|
16952
17134
|
try {
|
|
16953
17135
|
const existingMatch = this.findExisting(sourceObj, targetTickets, (t) => [t.title, t.description]);
|
|
17136
|
+
if (existingMatch) {
|
|
17137
|
+
alreadyPresentCount++;
|
|
17138
|
+
}
|
|
16954
17139
|
if (!existingMatch) {
|
|
16955
17140
|
const rawSource = sourceObj;
|
|
16956
17141
|
const ticketInput = {
|
|
@@ -17070,6 +17255,9 @@ class MatterportTagCopyService {
|
|
|
17070
17255
|
// Equipment has no `title`/`description`: it identifies itself by name, and by
|
|
17071
17256
|
// serial number when one is recorded.
|
|
17072
17257
|
const existingMatch = this.findExisting(sourceObj, targetEquipments, (e) => [e.name, e.serialNumber]);
|
|
17258
|
+
if (existingMatch) {
|
|
17259
|
+
alreadyPresentCount++;
|
|
17260
|
+
}
|
|
17073
17261
|
if (!existingMatch) {
|
|
17074
17262
|
const rawSource = sourceObj;
|
|
17075
17263
|
let copiedPhotoKey = null;
|
|
@@ -17249,6 +17437,9 @@ class MatterportTagCopyService {
|
|
|
17249
17437
|
const sourceObj = sourceObjects3D[i];
|
|
17250
17438
|
try {
|
|
17251
17439
|
const existsInTarget = targetObjects3D.some(targetObj => targetObj.name === sourceObj.name);
|
|
17440
|
+
if (existsInTarget) {
|
|
17441
|
+
alreadyPresentCount++;
|
|
17442
|
+
}
|
|
17252
17443
|
if (!existsInTarget) {
|
|
17253
17444
|
const rawSource = sourceObj;
|
|
17254
17445
|
// `path` means two different things depending on `s3Bucket`, exactly as the
|
|
@@ -17366,6 +17557,9 @@ class MatterportTagCopyService {
|
|
|
17366
17557
|
const sourceObj = sourceFeatures[i];
|
|
17367
17558
|
try {
|
|
17368
17559
|
const existingMatch = this.findExisting(sourceObj, targetFeatures, (f) => [f.title, f.description]);
|
|
17560
|
+
if (existingMatch) {
|
|
17561
|
+
alreadyPresentCount++;
|
|
17562
|
+
}
|
|
17369
17563
|
if (!existingMatch) {
|
|
17370
17564
|
const rawSource = sourceObj;
|
|
17371
17565
|
// Resolved just before the write: a keyword is only created in the target
|
|
@@ -17470,6 +17664,9 @@ class MatterportTagCopyService {
|
|
|
17470
17664
|
const sourceMeasurement = sourceMeasurements[i];
|
|
17471
17665
|
try {
|
|
17472
17666
|
const existsInTarget = targetMeasurements.some(tm => tm.comment.title === sourceMeasurement.comment.title);
|
|
17667
|
+
if (existsInTarget) {
|
|
17668
|
+
alreadyPresentCount++;
|
|
17669
|
+
}
|
|
17473
17670
|
if (!existsInTarget) {
|
|
17474
17671
|
const rawComment = sourceMeasurement.comment;
|
|
17475
17672
|
let copiedAnnexe = null;
|
|
@@ -17529,7 +17726,15 @@ class MatterportTagCopyService {
|
|
|
17529
17726
|
for (let i = 0; i < sourcePois.length; i++) {
|
|
17530
17727
|
const sourcePoi = sourcePois[i];
|
|
17531
17728
|
try {
|
|
17532
|
-
|
|
17729
|
+
// Compared on the parsed position, where the copy WOULD land: the stored strings
|
|
17730
|
+
// differ in format ('{ "x":' vs '{"x":') and, once landmarks move the tags, the
|
|
17731
|
+
// source string never equals its copy's, so every re-run duplicated these POIs.
|
|
17732
|
+
const expectedPosition = this.parseCoordinate(this.getAdjustedPositionOnly(sourcePoi.coordinate, transform));
|
|
17733
|
+
const existsInTarget = targetPois.some(tp => tp.tagDescription === sourcePoi.tagDescription
|
|
17734
|
+
&& this.isSamePosition(this.parseCoordinate(tp.coordinate), expectedPosition));
|
|
17735
|
+
if (existsInTarget) {
|
|
17736
|
+
alreadyPresentCount++;
|
|
17737
|
+
}
|
|
17533
17738
|
if (!existsInTarget) {
|
|
17534
17739
|
const elementID = sourcePoi.elementID
|
|
17535
17740
|
? (elementIds[sourcePoi.elementID] || sourcePoi.elementID)
|
|
@@ -17564,6 +17769,10 @@ class MatterportTagCopyService {
|
|
|
17564
17769
|
if (healedCount > 0) {
|
|
17565
17770
|
this.setStepLog('healedSummary', this.translate.instant('matterportCopy.healedSummary', { count: healedCount }));
|
|
17566
17771
|
}
|
|
17772
|
+
// Says plainly that a re-run created nothing new, instead of a bare "success".
|
|
17773
|
+
if (alreadyPresentCount > 0) {
|
|
17774
|
+
this.setStepLog('alreadyPresentSummary', this.translate.instant('matterportCopy.alreadyPresentSummary', { count: alreadyPresentCount }));
|
|
17775
|
+
}
|
|
17567
17776
|
return true;
|
|
17568
17777
|
}
|
|
17569
17778
|
catch (error) {
|
|
@@ -18320,6 +18529,28 @@ class MatterportTagCopyService {
|
|
|
18320
18529
|
yRotation: applyRigidTransformToYRotationDeg(parsed.yRotation, transform)
|
|
18321
18530
|
};
|
|
18322
18531
|
}
|
|
18532
|
+
/**
|
|
18533
|
+
* Reads a stored coordinate (JSON string or object, whatever its spacing) as a position.
|
|
18534
|
+
* Null for a virtual POI or an unreadable value.
|
|
18535
|
+
*/
|
|
18536
|
+
parseCoordinate(value) {
|
|
18537
|
+
try {
|
|
18538
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
18539
|
+
return parsed && typeof parsed.x === 'number'
|
|
18540
|
+
? { x: parsed.x, y: parsed.y, z: parsed.z }
|
|
18541
|
+
: null;
|
|
18542
|
+
}
|
|
18543
|
+
catch {
|
|
18544
|
+
return null;
|
|
18545
|
+
}
|
|
18546
|
+
}
|
|
18547
|
+
/** Two positions within 1 cm are the same (two virtual POIs, both null, are too). */
|
|
18548
|
+
isSamePosition(a, b, toleranceM = 0.01) {
|
|
18549
|
+
if (!a || !b) {
|
|
18550
|
+
return !a && !b;
|
|
18551
|
+
}
|
|
18552
|
+
return distance(a, b) <= toleranceM;
|
|
18553
|
+
}
|
|
18323
18554
|
/**
|
|
18324
18555
|
* Applies the rigid transform's translation+rotation to a plain {x,y,z} position,
|
|
18325
18556
|
* WITHOUT adding xRotation/yRotation keys. Used for measurements, whose stored
|
|
@@ -18545,13 +18776,403 @@ class MatterportTagCopyService {
|
|
|
18545
18776
|
// for the CopySource header. Do NOT re-encode it here.
|
|
18546
18777
|
return extracted;
|
|
18547
18778
|
}
|
|
18548
|
-
|
|
18779
|
+
/**
|
|
18780
|
+
* Both tag lists a recalibration can offer for a target space, computed in one pass. Only
|
|
18781
|
+
* the target location's own tags are ever listed (see RecalibrationTagScope); tags whose
|
|
18782
|
+
* element was deleted — orphan POIs — never are.
|
|
18783
|
+
* - `space`: every tag of the location, in any of its visits;
|
|
18784
|
+
* - `visit`: the tags of the location sitting on the sweeps of the selected target visit
|
|
18785
|
+
* (`options.targetNodeId`); empty when no visit is given.
|
|
18786
|
+
* With `options.onlyTagsInSource` and a source other than the target, both lists only keep
|
|
18787
|
+
* the tags that also exist in the source location (same identity as the copy's duplicate
|
|
18788
|
+
* detection): typically the tags an earlier copy brought over.
|
|
18789
|
+
*
|
|
18790
|
+
* A POI carries no name of its own: each tag gets `elementName`, the name of the element
|
|
18791
|
+
* it points at (ticket title, equipment name, ...).
|
|
18792
|
+
*/
|
|
18793
|
+
async getRecalibrationTagSets(sourceSpaceId, targetSpaceId, options = {}) {
|
|
18794
|
+
if (!sourceSpaceId || !targetSpaceId) {
|
|
18795
|
+
return { space: [], visit: [] };
|
|
18796
|
+
}
|
|
18797
|
+
const filterBySource = !!options.onlyTagsInSource && sourceSpaceId !== targetSpaceId;
|
|
18798
|
+
const [targetTags, sourceTags] = await Promise.all([
|
|
18799
|
+
this.loadLiveTagsForSpace(targetSpaceId, options.targetNodeId),
|
|
18800
|
+
filterBySource ? this.loadLiveTagsForSpace(sourceSpaceId) : Promise.resolve(null)
|
|
18801
|
+
]);
|
|
18802
|
+
const sourceKeys = sourceTags && new Set(sourceTags.filter(tag => tag.ownedBySpace).map(tag => tag.identity));
|
|
18803
|
+
const ownTargetTags = targetTags
|
|
18804
|
+
.filter(tag => tag.ownedBySpace)
|
|
18805
|
+
.filter(tag => !sourceKeys || sourceKeys.has(tag.identity));
|
|
18806
|
+
return {
|
|
18807
|
+
space: ownTargetTags.map(tag => tag.poi),
|
|
18808
|
+
visit: ownTargetTags.filter(tag => tag.inVisit).map(tag => tag.poi)
|
|
18809
|
+
};
|
|
18810
|
+
}
|
|
18811
|
+
/**
|
|
18812
|
+
* Signed, displayable URL of a tag's picture (`elementImageKey`). Meant to be called on
|
|
18813
|
+
* demand — when the tag is previewed — rather than for the whole list.
|
|
18814
|
+
*/
|
|
18815
|
+
async getTagImageUrl(imageKey) {
|
|
18816
|
+
const key = this.extractS3KeyFromValue(imageKey);
|
|
18817
|
+
return key ? getSignedFile(key) : null;
|
|
18818
|
+
}
|
|
18819
|
+
/**
|
|
18820
|
+
* Loads the POIs placed on the sweeps of a space whose element still exists, each with a
|
|
18821
|
+
* display name, an identity key and whether its element belongs to that space. The key
|
|
18822
|
+
* follows the same rules as the copy's duplicate detection (findExisting), so a tag and its
|
|
18823
|
+
* copy in another space share the same key. With a visit node, `inVisit` tells whether the
|
|
18824
|
+
* tag sits on one of that visit's sweeps.
|
|
18825
|
+
*/
|
|
18826
|
+
async loadLiveTagsForSpace(spaceId, visitNodeId) {
|
|
18827
|
+
const [pois, elements, zones] = await Promise.all([
|
|
18828
|
+
this.navigationService.getAllowedSweepsIDsForUserInSpace(spaceId)
|
|
18829
|
+
.then(sweepIds => this.poiService.getPoisByMatterportSweeps(sweepIds)),
|
|
18830
|
+
this.getTagElementsForSpace(spaceId),
|
|
18831
|
+
this.zoneService.getZonesBySpace(spaceId).catch(error => {
|
|
18832
|
+
console.error('Failed to load the zones of the space:', error);
|
|
18833
|
+
return [];
|
|
18834
|
+
})
|
|
18835
|
+
]);
|
|
18836
|
+
const sweepZones = this.getSweepZones(zones || []);
|
|
18837
|
+
const visitSweeps = visitNodeId ? await this.getSweepsOfVisit(visitNodeId, zones || []) : new Set();
|
|
18838
|
+
// A POI can point at an element stored under another space (left behind by an earlier
|
|
18839
|
+
// copy): those are not in the space-wide lists and are fetched by ID.
|
|
18840
|
+
const unresolved = (pois || []).filter(poi => poi?.elementID && !elements.has(poi.elementID));
|
|
18841
|
+
await this.fetchTagElementsById(unresolved, elements);
|
|
18842
|
+
const result = [];
|
|
18843
|
+
for (const poi of pois || []) {
|
|
18844
|
+
if (!poi) {
|
|
18845
|
+
continue;
|
|
18846
|
+
}
|
|
18847
|
+
let element;
|
|
18848
|
+
if (poi.elementID) {
|
|
18849
|
+
element = elements.get(poi.elementID);
|
|
18850
|
+
if (!element) {
|
|
18851
|
+
continue; // orphan: the element was deleted (or cannot be read)
|
|
18852
|
+
}
|
|
18853
|
+
}
|
|
18854
|
+
else {
|
|
18855
|
+
// standalone tag: its description is all that identifies it
|
|
18856
|
+
const description = this.stripHtml(poi.tagDescription);
|
|
18857
|
+
element = { name: description, identity: [description] };
|
|
18858
|
+
}
|
|
18859
|
+
const zones = sweepZones.get(poi.matterportSweepID);
|
|
18860
|
+
result.push({
|
|
18861
|
+
poi: {
|
|
18862
|
+
...poi,
|
|
18863
|
+
elementName: element.name,
|
|
18864
|
+
elementDescription: element.description,
|
|
18865
|
+
elementImageKey: element.imageKey,
|
|
18866
|
+
floorName: zones?.floor,
|
|
18867
|
+
zoneName: zones?.zone
|
|
18868
|
+
},
|
|
18869
|
+
identity: this.identityKey([poi.type, ...element.identity]),
|
|
18870
|
+
// decided by the element's own spaceID rather than by its presence in the
|
|
18871
|
+
// space-wide lists, some of which are not paginated. A standalone tag has no
|
|
18872
|
+
// element to tell: it belongs to every space that shows it.
|
|
18873
|
+
ownedBySpace: !poi.elementID || element.spaceId === spaceId,
|
|
18874
|
+
inVisit: visitSweeps.has(poi.matterportSweepID)
|
|
18875
|
+
});
|
|
18876
|
+
}
|
|
18877
|
+
return result;
|
|
18878
|
+
}
|
|
18879
|
+
/**
|
|
18880
|
+
* Sweeps of a virtual visit (a Node): those of the space's zones attached to that node,
|
|
18881
|
+
* else — zones not filled in for this visit — the sweeps of the node's navigations.
|
|
18882
|
+
*/
|
|
18883
|
+
async getSweepsOfVisit(nodeId, zones) {
|
|
18884
|
+
const sweeps = new Set(zones
|
|
18885
|
+
.filter(zone => zone.nodeIDs?.includes(nodeId))
|
|
18886
|
+
.flatMap(zone => zone.sweepIDs || []));
|
|
18887
|
+
if (sweeps.size === 0) {
|
|
18888
|
+
try {
|
|
18889
|
+
const navigations = await this.navigationService.getNavigationsForNode(nodeId);
|
|
18890
|
+
navigations.forEach(navigation => navigation.matterportSweepID && sweeps.add(navigation.matterportSweepID));
|
|
18891
|
+
}
|
|
18892
|
+
catch (error) {
|
|
18893
|
+
console.error('Failed to load the sweeps of the visit:', error);
|
|
18894
|
+
}
|
|
18895
|
+
}
|
|
18896
|
+
return sweeps;
|
|
18897
|
+
}
|
|
18898
|
+
/**
|
|
18899
|
+
* Maps each sweep of a space to the names of its floor (zone of layer FLOOR) and of its
|
|
18900
|
+
* most specific other zone (the one holding the fewest sweeps, typically a room, else the
|
|
18901
|
+
* visit's BUILDING zone).
|
|
18902
|
+
*/
|
|
18903
|
+
getSweepZones(zones) {
|
|
18904
|
+
const bySweep = new Map();
|
|
18905
|
+
const isFloor = (zone) => (zone.layer?.name || '').includes('FLOOR');
|
|
18906
|
+
const zoneRank = new Map(); // sweep -> sweep count of the zone kept so far
|
|
18907
|
+
for (const zone of zones) {
|
|
18908
|
+
for (const sweepId of zone.sweepIDs || []) {
|
|
18909
|
+
const entry = bySweep.get(sweepId) || {};
|
|
18910
|
+
if (isFloor(zone)) {
|
|
18911
|
+
entry.floor = entry.floor || zone.name;
|
|
18912
|
+
}
|
|
18913
|
+
else {
|
|
18914
|
+
const size = zone.sweepIDs.length;
|
|
18915
|
+
if (!zoneRank.has(sweepId) || size < zoneRank.get(sweepId)) {
|
|
18916
|
+
zoneRank.set(sweepId, size);
|
|
18917
|
+
entry.zone = zone.name;
|
|
18918
|
+
}
|
|
18919
|
+
}
|
|
18920
|
+
bySweep.set(sweepId, entry);
|
|
18921
|
+
}
|
|
18922
|
+
}
|
|
18923
|
+
return bySweep;
|
|
18924
|
+
}
|
|
18925
|
+
/**
|
|
18926
|
+
* Indexes, by ID, every element of a space a POI can point at. Each list is fetched
|
|
18927
|
+
* independently: one failing (module not enabled, missing permission) must not hide the
|
|
18928
|
+
* others — their POIs are then resolved one by one by fetchTagElementsById().
|
|
18929
|
+
*/
|
|
18930
|
+
async getTagElementsForSpace(spaceId) {
|
|
18931
|
+
const elements = new Map();
|
|
18932
|
+
const [tickets, equipments, objects3D, features, comments] = await Promise.allSettled([
|
|
18933
|
+
this.ticketService.getTicketsBySpace(spaceId),
|
|
18934
|
+
this.equipmentService.getEquipmentsForSpace(spaceId),
|
|
18935
|
+
this.object3DService.getObjects3DBySpace(spaceId),
|
|
18936
|
+
this.featureService.getAllFeaturesBySpaceRaw(spaceId),
|
|
18937
|
+
// a measurement POI is bound to the measurement's Comment, not to the measurement
|
|
18938
|
+
this.commentService.getCommentsBySpaceID(spaceId)
|
|
18939
|
+
]);
|
|
18940
|
+
const index = (settled, type) => {
|
|
18941
|
+
if (settled.status === 'fulfilled') {
|
|
18942
|
+
settled.value?.forEach(item => {
|
|
18943
|
+
if (item?.id) {
|
|
18944
|
+
elements.set(item.id, this.toTagElement(type, { spaceID: spaceId, ...item }));
|
|
18945
|
+
}
|
|
18946
|
+
});
|
|
18947
|
+
}
|
|
18948
|
+
};
|
|
18949
|
+
index(tickets, 'ticket');
|
|
18950
|
+
index(equipments, 'equipment');
|
|
18951
|
+
index(objects3D, 'object3D');
|
|
18952
|
+
index(features, 'feature');
|
|
18953
|
+
index(comments, 'comment');
|
|
18954
|
+
return elements;
|
|
18955
|
+
}
|
|
18956
|
+
/**
|
|
18957
|
+
* Fetches by ID the elements the space-wide lists did not return. The IDs are packed into
|
|
18958
|
+
* a few GraphQL requests using aliases (`e0: getTicket(id: ...) e1: getEquipment(...)`),
|
|
18959
|
+
* instead of one request per element: a space can hold over a thousand orphan POIs.
|
|
18960
|
+
* An element that no longer exists comes back as null and is simply not indexed.
|
|
18961
|
+
*/
|
|
18962
|
+
async fetchTagElementsById(pois, elements) {
|
|
18963
|
+
const IDS_PER_REQUEST = 100;
|
|
18964
|
+
const queries = {
|
|
18965
|
+
ticket: 'getTicket(id: $ID) { id spaceID title description }',
|
|
18966
|
+
equipment: 'getEquipment(id: $ID) { id spaceID name serialNumber }',
|
|
18967
|
+
object3D: 'getObject3D(id: $ID) { id spaceID name description }',
|
|
18968
|
+
comment: 'getComment(id: $ID) { id spaceID title description annexe }',
|
|
18969
|
+
feature: 'getFeature(id: $ID) { id spaceID title description }'
|
|
18970
|
+
};
|
|
18971
|
+
const pending = new Map();
|
|
18972
|
+
for (const poi of pois) {
|
|
18973
|
+
pending.set(poi.elementID, this.tagElementTypeOf(poi.type));
|
|
18974
|
+
}
|
|
18975
|
+
const entries = [...pending.entries()];
|
|
18976
|
+
const batches = [];
|
|
18977
|
+
for (let i = 0; i < entries.length; i += IDS_PER_REQUEST) {
|
|
18978
|
+
batches.push(entries.slice(i, i + IDS_PER_REQUEST));
|
|
18979
|
+
}
|
|
18980
|
+
await Promise.all(batches.map(async (batch) => {
|
|
18981
|
+
const fields = batch.map(([id, type], i) => `e${i}: ${queries[type].replace('$ID', JSON.stringify(id))}`);
|
|
18982
|
+
let data;
|
|
18983
|
+
try {
|
|
18984
|
+
data = (await API.graphql(graphqlOperation(`query TagElements { ${fields.join('\n')} }`))).data;
|
|
18985
|
+
}
|
|
18986
|
+
catch (error) {
|
|
18987
|
+
// Amplify rejects when ANY alias errors (e.g. an unreadable record), but still
|
|
18988
|
+
// hands over the data of the aliases that succeeded.
|
|
18989
|
+
data = error?.data;
|
|
18990
|
+
if (!data) {
|
|
18991
|
+
console.error('Failed to fetch tag elements by ID:', error);
|
|
18992
|
+
return;
|
|
18993
|
+
}
|
|
18994
|
+
}
|
|
18995
|
+
batch.forEach(([id, type], i) => {
|
|
18996
|
+
const item = data[`e${i}`];
|
|
18997
|
+
if (item) {
|
|
18998
|
+
elements.set(id, this.toTagElement(type, item));
|
|
18999
|
+
}
|
|
19000
|
+
});
|
|
19001
|
+
}));
|
|
19002
|
+
}
|
|
19003
|
+
/**
|
|
19004
|
+
* Moves a stored coordinate. Only the position and the horizontal orientation change:
|
|
19005
|
+
* every other key is kept as is. A coordinate often carries the tag's orientation next to
|
|
19006
|
+
* its position ({x, y, z, xRotation, yRotation}); rebuilding it from the position alone
|
|
19007
|
+
* silently erased that orientation.
|
|
19008
|
+
*/
|
|
19009
|
+
getRecalibratedCoordinate(coordinate, transform) {
|
|
19010
|
+
const position = applyRigidTransformToPoint({ x: coordinate.x, y: coordinate.y, z: coordinate.z }, transform);
|
|
19011
|
+
const moved = { ...coordinate, x: position.x, y: position.y, z: position.z };
|
|
19012
|
+
if ('yRotation' in coordinate) {
|
|
19013
|
+
moved.yRotation = applyRigidTransformToYRotationDeg(coordinate.yRotation, transform);
|
|
19014
|
+
}
|
|
19015
|
+
return moved;
|
|
19016
|
+
}
|
|
19017
|
+
/**
|
|
19018
|
+
* Reads POIs by ID, 100 per GraphQL request (aliases). Missing POIs are skipped. Amplify
|
|
19019
|
+
* rejects a request when ANY alias errors, but still hands over the data of the others:
|
|
19020
|
+
* those are kept, so one unreadable POI does not hide the 99 others of its batch.
|
|
19021
|
+
*/
|
|
19022
|
+
async fetchPoisById(ids) {
|
|
19023
|
+
const IDS_PER_REQUEST = 100;
|
|
19024
|
+
const uniqueIds = [...new Set(ids)];
|
|
19025
|
+
const batches = [];
|
|
19026
|
+
for (let i = 0; i < uniqueIds.length; i += IDS_PER_REQUEST) {
|
|
19027
|
+
batches.push(uniqueIds.slice(i, i + IDS_PER_REQUEST));
|
|
19028
|
+
}
|
|
19029
|
+
const results = await Promise.all(batches.map(async (batch) => {
|
|
19030
|
+
const fields = batch.map((id, i) => `p${i}: getPOI(id: ${JSON.stringify(id)}) { id coordinate metadata }`);
|
|
19031
|
+
let data;
|
|
19032
|
+
try {
|
|
19033
|
+
data = (await API.graphql(graphqlOperation(`query SelectedPois { ${fields.join('\n')} }`))).data;
|
|
19034
|
+
}
|
|
19035
|
+
catch (error) {
|
|
19036
|
+
data = error?.data;
|
|
19037
|
+
if (!data) {
|
|
19038
|
+
console.error('Failed to read the selected POIs:', error);
|
|
19039
|
+
return [];
|
|
19040
|
+
}
|
|
19041
|
+
}
|
|
19042
|
+
return batch.map((_, i) => data[`p${i}`]).filter(poi => !!poi);
|
|
19043
|
+
}));
|
|
19044
|
+
return results.flat();
|
|
19045
|
+
}
|
|
19046
|
+
tagElementTypeOf(poiType) {
|
|
19047
|
+
switch (poiType) {
|
|
19048
|
+
case PoiType.TICKET: return 'ticket';
|
|
19049
|
+
case PoiType.EQUIPMENT: return 'equipment';
|
|
19050
|
+
case PoiType.OBJECT3D: return 'object3D';
|
|
19051
|
+
case PoiType.MEASURE: return 'comment';
|
|
19052
|
+
default: return 'feature';
|
|
19053
|
+
}
|
|
19054
|
+
}
|
|
19055
|
+
/** Display name + identity fields of an element, per the copy's duplicate-detection rules. */
|
|
19056
|
+
toTagElement(type, item) {
|
|
19057
|
+
const spaceId = item.spaceID;
|
|
19058
|
+
const text = (value) => this.stripHtml(value) || undefined;
|
|
19059
|
+
switch (type) {
|
|
19060
|
+
case 'equipment':
|
|
19061
|
+
return { name: item.name || '', identity: [item.name, item.serialNumber], spaceId, description: text(item.description) };
|
|
19062
|
+
case 'object3D':
|
|
19063
|
+
return { name: item.name || '', identity: [item.name], spaceId, description: text(item.description) };
|
|
19064
|
+
case 'comment':
|
|
19065
|
+
// A measurement's title is usually empty: its description holds the dimensions and
|
|
19066
|
+
// becomes the name. Its picture is the screenshot taken when it was measured.
|
|
19067
|
+
return {
|
|
19068
|
+
name: item.title || item.description || '',
|
|
19069
|
+
identity: [item.title, item.description],
|
|
19070
|
+
spaceId,
|
|
19071
|
+
description: item.title ? text(item.description) : undefined,
|
|
19072
|
+
imageKey: item.annexe || undefined
|
|
19073
|
+
};
|
|
19074
|
+
default:
|
|
19075
|
+
return { name: item.title || '', identity: [item.title, item.description], spaceId, description: text(item.description) };
|
|
19076
|
+
}
|
|
19077
|
+
}
|
|
19078
|
+
stripHtml(value) {
|
|
19079
|
+
return (value || '').replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
19080
|
+
}
|
|
19081
|
+
/**
|
|
19082
|
+
* Recalibrates a specific list of existing tags in the target space by applying the rigid
|
|
19083
|
+
* transformation calculated from the selected landmark points.
|
|
19084
|
+
*
|
|
19085
|
+
* Each tag is updated on its own: a failing update is logged and counted, it no longer
|
|
19086
|
+
* stops the remaining tags. Progress and log go through copyProgress$ / copyLog$, like a
|
|
19087
|
+
* copy (phase 'recalibrating'). `tagLabels` (tag id -> name) only makes the log readable.
|
|
19088
|
+
*/
|
|
19089
|
+
async recalibrateTagsFromVisit(targetSpaceId, selectedTagIds, landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB, tagLabels = {}) {
|
|
19090
|
+
const result = { updated: 0, skipped: 0, failed: 0 };
|
|
19091
|
+
const uniqueIds = [...new Set(selectedTagIds)];
|
|
19092
|
+
const total = uniqueIds.length;
|
|
19093
|
+
const label = (id) => tagLabels[id] || `#${id.substring(0, 8)}`;
|
|
19094
|
+
let processed = 0;
|
|
19095
|
+
const emitProgress = (phase) => {
|
|
19096
|
+
this.copyProgress$.next({
|
|
19097
|
+
phase,
|
|
19098
|
+
processedInPhase: processed, totalInPhase: total,
|
|
19099
|
+
processedOverall: processed, totalOverall: total,
|
|
19100
|
+
percent: total > 0 ? Math.round((processed / total) * 100) : 100,
|
|
19101
|
+
errorCount: result.failed, healedCount: 0
|
|
19102
|
+
});
|
|
19103
|
+
this.setStepLog('recalibrating', this.translate.instant('matterportCopy.recalibrateStep', { processed, total }));
|
|
19104
|
+
};
|
|
19105
|
+
this.resetLog();
|
|
19106
|
+
emitProgress('recalibrating');
|
|
19107
|
+
try {
|
|
19108
|
+
const transform = computeRigidTransform(landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB);
|
|
19109
|
+
// Re-read only the selected POIs, by ID, so the transform is applied to their current
|
|
19110
|
+
// position — scanning the whole space again for a handful of tags was the slow path.
|
|
19111
|
+
const targetPois = await this.fetchPoisById(uniqueIds);
|
|
19112
|
+
const foundIds = new Set(targetPois.map(poi => poi.id));
|
|
19113
|
+
uniqueIds.filter(id => !foundIds.has(id)).forEach(id => {
|
|
19114
|
+
result.skipped++;
|
|
19115
|
+
processed++;
|
|
19116
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.recalibrateNotFound', { name: label(id) }));
|
|
19117
|
+
});
|
|
19118
|
+
emitProgress('recalibrating');
|
|
19119
|
+
const UPDATES_IN_PARALLEL = 10;
|
|
19120
|
+
for (let i = 0; i < targetPois.length; i += UPDATES_IN_PARALLEL) {
|
|
19121
|
+
await Promise.all(targetPois.slice(i, i + UPDATES_IN_PARALLEL).map(async (poi) => {
|
|
19122
|
+
const id = poi.id;
|
|
19123
|
+
try {
|
|
19124
|
+
let originalCoord = null;
|
|
19125
|
+
try {
|
|
19126
|
+
originalCoord = typeof poi.coordinate === 'string'
|
|
19127
|
+
? JSON.parse(poi.coordinate)
|
|
19128
|
+
: poi.coordinate;
|
|
19129
|
+
}
|
|
19130
|
+
catch {
|
|
19131
|
+
originalCoord = null;
|
|
19132
|
+
}
|
|
19133
|
+
if (!originalCoord || typeof originalCoord.x !== 'number') {
|
|
19134
|
+
// virtual POI or unreadable coordinate: no position to move
|
|
19135
|
+
result.skipped++;
|
|
19136
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.recalibrateSkipped', { name: label(id) }));
|
|
19137
|
+
return;
|
|
19138
|
+
}
|
|
19139
|
+
await this.poiService.updatePoi({
|
|
19140
|
+
id,
|
|
19141
|
+
coordinate: JSON.stringify(this.getRecalibratedCoordinate(originalCoord, transform)),
|
|
19142
|
+
metadata: this.getAdjustedPoiMetadata(poi.metadata, transform)
|
|
19143
|
+
});
|
|
19144
|
+
result.updated++;
|
|
19145
|
+
}
|
|
19146
|
+
catch (error) {
|
|
19147
|
+
result.failed++;
|
|
19148
|
+
console.error(`Failed to recalibrate the tag ${id}:`, error);
|
|
19149
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.recalibrateError', { name: label(id), error: toErrorMessage(error) }));
|
|
19150
|
+
}
|
|
19151
|
+
finally {
|
|
19152
|
+
processed++;
|
|
19153
|
+
emitProgress('recalibrating');
|
|
19154
|
+
}
|
|
19155
|
+
}));
|
|
19156
|
+
}
|
|
19157
|
+
}
|
|
19158
|
+
catch (error) {
|
|
19159
|
+
// transform or reading failure: nothing left can be moved
|
|
19160
|
+
console.error('Erreur lors du recalibrage des tags:', error);
|
|
19161
|
+
result.failed = total - result.updated - result.skipped;
|
|
19162
|
+
processed = total;
|
|
19163
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.errorGeneral', { error: toErrorMessage(error) }));
|
|
19164
|
+
}
|
|
19165
|
+
emitProgress('done');
|
|
19166
|
+
this.setStepLog('done', this.translate.instant('matterportCopy.recalibrateSummary', result));
|
|
19167
|
+
return result;
|
|
19168
|
+
}
|
|
19169
|
+
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
19170
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, providedIn: 'root' });
|
|
18550
19171
|
}
|
|
18551
19172
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, decorators: [{
|
|
18552
19173
|
type: Injectable,
|
|
18553
19174
|
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 }] });
|
|
19175
|
+
}], 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
19176
|
|
|
18556
19177
|
/* eslint-disable class-methods-use-this */
|
|
18557
19178
|
class OrganisationService {
|