Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ A set of Python scripts and notebooks to help configure maps and manage data for
- [Proxy Esri Basemaps for ArcGIS Enterprise Offline Map Areas](notebooks/Proxy%20Esri%20Basemaps%20for%20ArcGIS%20Enterprise%20Offline%20Map%20Areas.ipynb)
- [Watermark photo attachments with Exif data](notebooks/Watermark%20photo%20attachments%20with%20Exif%20data.ipynb)
- [Offline Checks](notebooks/Offline%20Checks.ipynb)
- [Workforce Tasks Migration](notebooks/Workforce%20Tasks%20Migration)

### Requirements

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Add required fields Tasks for point, line, polygon layers\n",
"\n",
"This notebook updates the schema of an existing point, line or polygon feature layer, preparing it to support the Tasks functionality in ArcGIS Field Maps.\n",
"\n",
"The notebook performs the following actions:\n",
"\n",
"- Adds a series of fields and necessary domains\n",
"- Enables attachments if needed \n",
"\n",
"Note: you must be the owner of the feature layer or an organization admin user\n",
"\n",
"### Steps\n",
"\n",
"0. Identify a hosted feature layer that you want to enable with tasks. Edit tracking and sync should be enabled.\n",
"\n",
"1. Update the following variables\n",
"\n",
" - `ITEM_ID`\n",
" - `FEATURE_LAYER_INDEX`\n",
" - `WORKFORCE_FS_ID`\n",
" - `ASSIGN_TABLE_INDEX`\n",
"\n",
"2. Run all cells\n",
"\n",
"\n",
"Reference:\n",
"Tasks Information Model: https://doc.arcgis.com/en/field-maps/latest/prepare-maps/prepare-tasks.htm#ESRI_SECTION1_3BBDB65A5B75485D89FC4BE0F92A32BC\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"# Import libraries\n",
"from arcgis.gis import GIS\n",
"from arcgis.features import FeatureLayerCollection\n",
"import uuid"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sign in to organization\n",
"PORTAL_URL = 'https://www.arcgis.com' # ArcGIS Online, or your Enterprise URL\n",
"username = input('Enter username: ')\n",
"\n",
"gis = GIS(PORTAL_URL, username)\n",
"# gis = GIS('home') # use this method when running as a hosted notebook in AGOL/Enterprise\n",
"\n",
"print(f'Connected as: {gis.properties.user.username}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"# update this information prior to running\n",
"ITEM_ID = '' # item_id of feature layer\n",
"FEATURE_LAYER_INDEX = 0 # index of layer you want to update\n",
"\n",
"# get the feature layer by ID\n",
"item = gis.content.get(ITEM_ID)\n",
"\n",
"if item is None:\n",
" raise TypeError('Cannot Find item')\n",
"\n",
"# check the item type is a feature service\n",
"if item.type != 'Feature Service':\n",
" raise TypeError('Item is not a feature service')\n",
"\n",
"feature_layer_collection = FeatureLayerCollection.fromitem(item)\n",
"\n",
"feature_layer = feature_layer_collection.layers[FEATURE_LAYER_INDEX]\n",
"\n",
"# get the geometry type\n",
"geometry_type = feature_layer.properties.geometryType\n",
"\n",
"# make sure layer is a point, line, or polygon layer\n",
"if (\n",
" (geometry_type != 'esriGeometryPolyline')\n",
" and (geometry_type != 'esriGeometryPolygon')\n",
" and (geometry_type != 'esriGeometryPoint')\n",
"):\n",
" raise TypeError('Feature layer is not a point, line, or polygon layer')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Workforce Assigment Types (Optional)**\n",
"If your task layer originated from a workforce project, especially if you ran the workforce_flat_service notebook to create it, you may want to bring your Assignment Type values from Workforce and apply them to the domain of the esritask_type field. Use the next cell to pass in your Workforce feature service ID and create the function to gather the domain values."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"WORKFORCE_FS_ID = '' # enter the item ID of your workforce assignment table\n",
"ASSIGN_TABLE_INDEX = 1 # enter the index of the assignment type table\n",
"\n",
"wf_item = gis.content.get(WORKFORCE_FS_ID)\n",
"\n",
"if wf_item is None:\n",
" raise TypeError('Cannot Find item')\n",
"\n",
"flc = FeatureLayerCollection.fromitem(wf_item)\n",
"\n",
"# check the index of the assignment type table\n",
"if flc.tables[ASSIGN_TABLE_INDEX].properties.name != 'Assignment Types':\n",
" raise TypeError('Please enter the table index of your assignment type table')\n",
"\n",
"# query the assignment type table for unique descriptions\n",
"assignment_types_query = flc.tables[ASSIGN_TABLE_INDEX].query(\n",
" out_fields='description', return_distinct_values=True\n",
")\n",
"assignment_types = [f.attributes['description'] for f in assignment_types_query]\n",
"\n",
"if not assignment_types:\n",
" print('No assignment types found')\n",
"else:\n",
" print('All assignment types from Workforce project:')\n",
" print(assignment_types)\n",
"\n",
"cv_list = [{'name': t, 'code': i} for i, t in enumerate(assignment_types)]\n",
"\n",
"DEFAULT_DOMAIN_CODES = [\n",
" {'name': 'Python Added Fields 1', 'code': 0},\n",
" {'name': 'Python Added Fields 2', 'code': 1},\n",
"]\n",
"\n",
"domain_codes = cv_list or DEFAULT_DOMAIN_CODES"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"# Ensure all fields are present; if not, add them to the definition\n",
"\n",
"# Get existing fields from feature service and create lowercase field list\n",
"feature_layer_fields = [field['name'].lower() for field in feature_layer.properties.fields]\n",
"\n",
"# new fields which need to be added\n",
"tasks_fields = {'fields': []}\n",
"\n",
"# esritask_type\n",
"if 'esritask_type' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_type',\n",
" 'type': 'esriFieldTypeInteger',\n",
" 'alias': 'Task Type',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': True,\n",
" 'editable': True,\n",
" 'domain': {'type': 'codedValue',\n",
" 'name': 'ESRITASK_TYPE_DOMAIN_' + str(uuid.uuid4()),\n",
" 'codedValues': domain_codes},\n",
" 'defaultValue': 0})\n",
"\n",
"# esritask_status\n",
"if 'esritask_status' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_status',\n",
" 'type': 'esriFieldTypeInteger',\n",
" 'alias': 'Status',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': True,\n",
" 'editable': True,\n",
" 'domain': {'type': 'codedValue',\n",
" 'name': 'ESRITASK_STATUS_DOMAIN_' + str(uuid.uuid4()),\n",
" 'codedValues': [\n",
" {'name': 'Unassigned', 'code': 0},\n",
" {'name': 'Assigned', 'code': 1},\n",
" {'name': 'In Progress', 'code': 2},\n",
" {'name': 'Completed', 'code': 3}]},\n",
" 'defaultValue': 0})\n",
"\n",
"# esritask_assignee\n",
"if 'esritask_assignee' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_assignee',\n",
" 'type': 'esriFieldTypeString',\n",
" 'alias': 'Assignee',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'length': 255,\n",
" 'nullable': True,\n",
" 'editable': True,\n",
" 'domain': {'type': 'codedValue',\n",
" 'name': 'ESRITASK_ASSIGNEE_DOMAIN_' + str(uuid.uuid4()),\n",
" 'codedValues': [\n",
" {'name': 'Assignee name 1', 'code': 'assignee_username_1'},\n",
" {'name': 'Assignee name 2', 'code': 'assignee_username_2'}]},\n",
" 'defaultValue': None})\n",
"\n",
"# esritask_priority\n",
"if 'esritask_priority' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_priority',\n",
" 'type': 'esriFieldTypeInteger',\n",
" 'alias': 'Priority',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': True,\n",
" 'editable': True,\n",
" 'domain': {'type': 'codedValue',\n",
" 'name': 'ESRITASK_PRIORITY_DOMAIN_' + str(uuid.uuid4()),\n",
" 'codedValues': [\n",
" {'name': 'None', 'code': 0},\n",
" {'name': 'Low', 'code': 1},\n",
" {'name': 'Medium', 'code': 2},\n",
" {'name': 'High', 'code': 3},\n",
" {'name': 'Critical', 'code': 4}]},\n",
" 'defaultValue': 0})\n",
"\n",
"# esritask_duedate\n",
"if 'esritask_duedate' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_duedate',\n",
" 'type': 'esriFieldTypeDate',\n",
" 'alias': 'Due Date',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': True,\n",
" 'editable': True})\n",
"\n",
"# esritask_description\n",
"if 'esritask_description' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_description',\n",
" 'type': 'esriFieldTypeString',\n",
" 'alias': 'Description',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': True,\n",
" 'editable': True,\n",
" 'length':4000})\n",
"\n",
"# esritask_notes\n",
"if 'esritask_notes' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'esritask_notes',\n",
" 'type': 'esriFieldTypeString',\n",
" 'alias': 'Notes',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': True,\n",
" 'editable': True,\n",
" 'length':4000})\n",
"\n",
"# GlobalID\n",
"if 'globalid' not in feature_layer_fields:\n",
" tasks_fields['fields'].append({'name': 'GlobalID',\n",
" 'type': 'esriFieldTypeGlobalID',\n",
" 'alias': 'GlobalID',\n",
" 'sqlType': 'sqlTypeOther',\n",
" 'nullable': False,\n",
" 'editable': False,\n",
" 'defaultValue': 'NEWID() WITH VALUES'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"# Add task fields to the layer definition when there are missing fields.\n",
"new_fields_count = len(tasks_fields['fields'])\n",
"\n",
"if new_fields_count == 0:\n",
" print('No changes to task fields.')\n",
"else:\n",
" response = feature_layer.manager.add_to_definition(tasks_fields)\n",
" result = response.get('success', False)\n",
"\n",
" if result:\n",
" print(f'Successfully added {new_fields_count} task field(s).')\n",
" print('Service definition updated successfully.')\n",
" else:\n",
" print('Failed to update feature layer service definition.')\n",
" print(response)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "gis_env_hc",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.15"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading
Loading