[Maps] Prevent overwriting managed content from the editor (#175329)

## Summary

Close https://github.com/elastic/kibana/issues/172381

I marked this a breaking change since it is preventing users from doing
something they have been able to do before. They can no longer save
changes to managed map. Instead, they have to save changes to a new map.

To test, import this `ndjson` file which includes a managed map:

<details>

```
{"attributes":{"allowHidden":false,"fieldAttrs":"{}","fieldFormatMap":"{}","fields":"[]","name":"school_neighborhood_poverty_estimates_-_current","runtimeFieldMap":"{}","sourceFilters":"[]","title":"school_neighborhood_poverty_estimates_-_current"},"coreMigrationVersion":"8.8.0","created_at":"2024-01-23T16:29:10.798Z","id":"5162dd45-e7b8-41a4-816d-b427f0be7194","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2024-01-23T16:29:10.798Z","version":"WzYsMV0="}
{"attributes":{"description":"","layerListJSON":"[{\"locale\":\"autoselect\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\"},\"id\":\"b093ef75-9c58-4fad-a029-a10f09bafc3e\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"EMS_VECTOR_TILE\",\"color\":\"\"},\"includeInFitToBounds\":true,\"type\":\"EMS_VECTOR_TILE\"},{\"sourceDescriptor\":{\"geoField\":\"geometry\",\"scalingType\":\"MVT\",\"id\":\"47944ba6-77b4-419e-bc90-8443bd86d529\",\"type\":\"ES_SEARCH\",\"applyGlobalQuery\":true,\"applyGlobalTime\":true,\"applyForceRefresh\":true,\"filterByMapBounds\":true,\"tooltipProperties\":[],\"sortField\":\"\",\"sortOrder\":\"desc\",\"topHitsGroupByTimeseries\":false,\"topHitsSplitField\":\"\",\"topHitsSize\":1,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"id\":\"807664cf-ae19-4b64-8f2e-3d917e35f3ab\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}},\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#54B399\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#41937c\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":0}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":6}},\"iconOrientation\":{\"type\":\"STATIC\",\"options\":{\"orientation\":0}},\"labelText\":{\"type\":\"STATIC\",\"options\":{\"value\":\"\"}},\"labelColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#000000\"}},\"labelSize\":{\"type\":\"STATIC\",\"options\":{\"size\":14}},\"labelZoomRange\":{\"options\":{\"useLayerZoomRange\":true,\"minZoom\":0,\"maxZoom\":24}},\"labelBorderColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"labelBorderSize\":{\"options\":{\"size\":\"SMALL\"}},\"labelPosition\":{\"options\":{\"position\":\"CENTER\"}}},\"isTimeAware\":true},\"includeInFitToBounds\":true,\"type\":\"MVT_VECTOR\",\"joins\":[],\"disableTooltips\":false}]","mapStateJSON":"{\"adHocDataViews\":[],\"zoom\":9.06,\"center\":{\"lon\":-112.43427,\"lat\":33.76472},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":60000},\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filters\":[],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"customIcons\":[],\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"keydownScrollZoom\":false,\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"showTimesliderToggleButton\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}","title":"My map","uiStateJSON":"{\"isLayerTOCOpen\":true,\"openTOCDetails\":[]}"},"coreMigrationVersion":"8.8.0","created_at":"2024-01-23T16:27:07.764Z","id":"8359b071-6da7-43dc-b375-3d0afa546763","managed":true,"references":[{"id":"5162dd45-e7b8-41a4-816d-b427f0be7194","name":"layer_1_source_index_pattern","type":"index-pattern"}],"type":"map","typeMigrationVersion":"8.4.0","updated_at":"2024-01-23T16:32:59.750Z","version":"WzcsMV0="}
{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":2,"missingRefCount":0,"missingReferences":[]}
```
</details>

This is how the UI should look:

<img width="1037" alt="Screenshot 2024-01-23 at 9 39 48 AM"
src="45e50364-d947-486e-9295-f63d56bb7f18">


### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed —
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4968
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Drew Tate 2024-01-30 14:49:46 -07:00 committed by GitHub
parent 25ef250db6
commit 1aea4ba38e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 55 additions and 1 deletions

View file

@ -7,3 +7,7 @@
{"attributes":{"columns":["@tags","clientip"],"description":"","grid":{},"hideChart":false,"isTextBasedQuery":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"agent.raw:\\\"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\\\" \",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["@timestamp","desc"]],"timeRestore":false,"title":"Saved search","usesAdHocDataView":false},"coreMigrationVersion":"8.8.0","created_at":"2024-01-22T18:11:05.016Z","id":"managed-3d62-4113-ac7c-de2e20a68fbc","managed":true,"references":[{"id":"5f863f70-4728-4e8d-b441-db08f8c33b28","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","typeMigrationVersion":"8.0.0","updated_at":"2024-01-22T18:11:05.016Z","version":"WzIzLDFd"}
{"attributes":{"columns":["@tags","clientip"],"description":"","grid":{},"hideChart":false,"isTextBasedQuery":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"agent.raw:\\\"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\\\" \",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["@timestamp","desc"]],"timeRestore":false,"title":"Saved search","usesAdHocDataView":false},"coreMigrationVersion":"8.8.0","created_at":"2024-01-22T18:11:05.016Z","id":"unmanaged-3d62-4113-ac7c-de2e20a68fbc","managed":false,"references":[{"id":"5f863f70-4728-4e8d-b441-db08f8c33b28","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","typeMigrationVersion":"8.0.0","updated_at":"2024-01-22T18:11:05.016Z","version":"WzIzLDFd"}
{"attributes":{"description":"","layerListJSON":"[{\"locale\":\"autoselect\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\"},\"id\":\"5ff9c98e-e0d3-4aff-ac98-b33c191496b4\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"EMS_VECTOR_TILE\",\"color\":\"\"},\"includeInFitToBounds\":true,\"type\":\"EMS_VECTOR_TILE\"}]","mapStateJSON":"{\"adHocDataViews\":[],\"zoom\":1.4,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":60000},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"customIcons\":[],\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"keydownScrollZoom\":false,\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"showTimesliderToggleButton\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}","title":"Map","uiStateJSON":"{\"isLayerTOCOpen\":true,\"openTOCDetails\":[]}"},"coreMigrationVersion":"8.8.0","created_at":"2024-01-24T18:22:40.360Z","id":"managed-d7ab-46eb-a807-8fed28ed8566","managed":true,"references":[],"type":"map","typeMigrationVersion":"8.4.0","updated_at":"2024-01-24T18:23:07.090Z","version":"WzEyLDFd"}
{"attributes":{"description":"","layerListJSON":"[{\"locale\":\"autoselect\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\"},\"id\":\"5ff9c98e-e0d3-4aff-ac98-b33c191496b4\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"EMS_VECTOR_TILE\",\"color\":\"\"},\"includeInFitToBounds\":true,\"type\":\"EMS_VECTOR_TILE\"}]","mapStateJSON":"{\"adHocDataViews\":[],\"zoom\":1.4,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":60000},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"customIcons\":[],\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"keydownScrollZoom\":false,\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"showTimesliderToggleButton\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}","title":"Map","uiStateJSON":"{\"isLayerTOCOpen\":true,\"openTOCDetails\":[]}"},"coreMigrationVersion":"8.8.0","created_at":"2024-01-24T18:22:40.360Z","id":"unmanaged-d7ab-46eb-a807-8fed28ed8566","managed":false,"references":[],"type":"map","typeMigrationVersion":"8.4.0","updated_at":"2024-01-24T18:23:07.090Z","version":"WzEyLDFd"}

View file

@ -28,6 +28,8 @@ type MapDoc = MapAttributes & {
};
export interface MapUnwrapMetaInfo {
sharingSavedObjectProps: SharingSavedObjectProps;
// Is this map managed by the system?
managed: boolean;
}
export type MapAttributeService = AttributeService<
@ -101,6 +103,7 @@ export function getMapAttributeService(): MapAttributeService {
aliasPurpose,
sourceId: savedObjectId,
},
managed: Boolean(savedObject.managed),
},
};
},

View file

@ -32,6 +32,7 @@ import {
withNotifyOnErrors,
IKbnUrlStateStorage,
} from '@kbn/kibana-utils-plugin/public';
import { getManagedContentBadge } from '@kbn/managed-content-badge';
import {
getData,
getExecutionContextService,
@ -486,6 +487,18 @@ export class MapApp extends React.Component<Props, State> {
<TopNavMenu
setMenuMountPoint={this.props.setHeaderActionMenu}
appName={APP_ID}
badges={
this.props.savedMap.isManaged()
? [
getManagedContentBadge(
i18n.translate('xpack.maps.mapController.managedMapDescriptionTooltip', {
defaultMessage:
'This map is managed by Elastic. Changes here must be saved to a new map.',
})
),
]
: undefined
}
config={topNavConfig}
indexPatterns={this.state.indexPatterns}
filters={this.props.filters}

View file

@ -85,6 +85,7 @@ export class SavedMap {
private readonly _store: MapStore;
private _tags: string[] = [];
private _defaultLayerWizard: string;
private _managed: boolean;
constructor({
defaultLayers = [],
@ -114,6 +115,7 @@ export class SavedMap {
this._stateTransfer = stateTransfer;
this._store = createMapStore();
this._defaultLayerWizard = defaultLayerWizard || '';
this._managed = false;
}
public getStore() {
@ -137,6 +139,7 @@ export class SavedMap {
if (metaInfo?.sharingSavedObjectProps) {
this._sharingSavedObjectProps = metaInfo.sharingSavedObjectProps;
}
this._managed = Boolean(metaInfo?.managed);
const savedObjectsTagging = getSavedObjectsTagging();
if (savedObjectsTagging && references && references.length) {
this._tags = savedObjectsTagging.ui.getTagIdsFromReferences(references);
@ -430,6 +433,10 @@ export class SavedMap {
return this._sharingSavedObjectProps;
}
public isManaged(): boolean {
return this._managed;
}
public isByValue(): boolean {
const hasSavedObjectId = !!this.getSavedObjectId();
return getIsAllowByValueEmbeddables() && !!this._originatingApp && !hasSavedObjectId;

View file

@ -240,6 +240,14 @@ export function getTopNavConfig({
<SavedObjectSaveModalDashboard
{...saveModalProps}
canSaveByReference={true} // we know here that we have save capabilities.
mustCopyOnSaveMessage={
savedMap.isManaged()
? i18n.translate('xpack.maps.topNav.mustCopyOnSaveMessage', {
defaultMessage:
'This map is managed by Elastic. Changes here must be saved to a new map.',
})
: undefined
}
tagOptions={tagSelector}
/>
);

View file

@ -83,6 +83,7 @@
"@kbn/es-types",
"@kbn/data-service",
"@kbn/code-editor",
"@kbn/managed-content-badge",
"@kbn/presentation-publishing",
],
"exclude": [

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects(['timePicker', 'lens', 'common', 'discover']);
const PageObjects = getPageObjects(['timePicker', 'lens', 'common', 'discover', 'maps']);
const kibanaServer = getService('kibanaServer');
const esArchiver = getService('esArchiver');
const testSubjects = getService('testSubjects');
@ -76,5 +76,23 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await expectManagedContentSignifiers(false, 'discoverSaveButton');
});
it('maps', async () => {
await PageObjects.common.navigateToActualUrl(
'maps',
'map/managed-d7ab-46eb-a807-8fed28ed8566'
);
await PageObjects.maps.waitForLayerAddPanelClosed();
await expectManagedContentSignifiers(true, 'mapSaveButton');
await PageObjects.common.navigateToActualUrl(
'maps',
'map/unmanaged-d7ab-46eb-a807-8fed28ed8566'
);
await PageObjects.maps.waitForLayerAddPanelClosed();
await expectManagedContentSignifiers(false, 'mapSaveButton');
});
});
}