@saschabrunnerch/arcgis-maps-sdk-js-ai-context 0.0.1
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/LICENSE +21 -0
- package/README.md +201 -0
- package/bin/cli.js +173 -0
- package/contexts/4.34/claude/arcgis-3d-advanced/SKILL.md +586 -0
- package/contexts/4.34/claude/arcgis-advanced-layers/SKILL.md +431 -0
- package/contexts/4.34/claude/arcgis-analysis-services/SKILL.md +607 -0
- package/contexts/4.34/claude/arcgis-arcade/SKILL.md +366 -0
- package/contexts/4.34/claude/arcgis-authentication/SKILL.md +301 -0
- package/contexts/4.34/claude/arcgis-cim-symbols/SKILL.md +486 -0
- package/contexts/4.34/claude/arcgis-coordinates-projection/SKILL.md +406 -0
- package/contexts/4.34/claude/arcgis-core-maps/SKILL.md +739 -0
- package/contexts/4.34/claude/arcgis-core-utilities/SKILL.md +732 -0
- package/contexts/4.34/claude/arcgis-custom-rendering/SKILL.md +445 -0
- package/contexts/4.34/claude/arcgis-editing-advanced/SKILL.md +702 -0
- package/contexts/4.34/claude/arcgis-feature-effects/SKILL.md +393 -0
- package/contexts/4.34/claude/arcgis-geometry-operations/SKILL.md +489 -0
- package/contexts/4.34/claude/arcgis-imagery/SKILL.md +307 -0
- package/contexts/4.34/claude/arcgis-interaction/SKILL.md +572 -0
- package/contexts/4.34/claude/arcgis-knowledge-graphs/SKILL.md +582 -0
- package/contexts/4.34/claude/arcgis-layers/SKILL.md +601 -0
- package/contexts/4.34/claude/arcgis-map-tools/SKILL.md +668 -0
- package/contexts/4.34/claude/arcgis-media-layers/SKILL.md +290 -0
- package/contexts/4.34/claude/arcgis-popup-templates/SKILL.md +891 -0
- package/contexts/4.34/claude/arcgis-portal-content/SKILL.md +679 -0
- package/contexts/4.34/claude/arcgis-scene-effects/SKILL.md +512 -0
- package/contexts/4.34/claude/arcgis-smart-mapping/SKILL.md +686 -0
- package/contexts/4.34/claude/arcgis-tables-forms/SKILL.md +877 -0
- package/contexts/4.34/claude/arcgis-time-animation/SKILL.md +722 -0
- package/contexts/4.34/claude/arcgis-utility-networks/SKILL.md +301 -0
- package/contexts/4.34/claude/arcgis-visualization/SKILL.md +580 -0
- package/contexts/4.34/claude/arcgis-widgets-ui/SKILL.md +574 -0
- package/contexts/4.34/copilot/arcgis-3d.instructions.md +267 -0
- package/contexts/4.34/copilot/arcgis-analysis.instructions.md +294 -0
- package/contexts/4.34/copilot/arcgis-arcade.instructions.md +234 -0
- package/contexts/4.34/copilot/arcgis-authentication.instructions.md +187 -0
- package/contexts/4.34/copilot/arcgis-cim-symbols.instructions.md +177 -0
- package/contexts/4.34/copilot/arcgis-core-maps.instructions.md +246 -0
- package/contexts/4.34/copilot/arcgis-core-utilities.instructions.md +247 -0
- package/contexts/4.34/copilot/arcgis-editing.instructions.md +262 -0
- package/contexts/4.34/copilot/arcgis-geometry.instructions.md +225 -0
- package/contexts/4.34/copilot/arcgis-layers.instructions.md +278 -0
- package/contexts/4.34/copilot/arcgis-popup-templates.instructions.md +266 -0
- package/contexts/4.34/copilot/arcgis-portal-advanced.instructions.md +275 -0
- package/contexts/4.34/copilot/arcgis-smart-mapping.instructions.md +184 -0
- package/contexts/4.34/copilot/arcgis-time-animation.instructions.md +112 -0
- package/contexts/4.34/copilot/arcgis-visualization.instructions.md +321 -0
- package/contexts/4.34/copilot/arcgis-widgets-ui.instructions.md +277 -0
- package/lib/installer.js +379 -0
- package/package.json +45 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: arcgis-arcade
|
|
3
|
+
description: Write Arcade expressions for dynamic calculations in popups, renderers, labels, and field calculations. Use for data-driven styling, custom labels, and computed fields.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ArcGIS Arcade Expressions
|
|
7
|
+
|
|
8
|
+
Use this skill for writing Arcade expressions for popups, renderers, labels, and calculations.
|
|
9
|
+
|
|
10
|
+
## Arcade Basics
|
|
11
|
+
|
|
12
|
+
Arcade is an expression language for ArcGIS. It's used for:
|
|
13
|
+
- Dynamic popup content
|
|
14
|
+
- Data-driven rendering
|
|
15
|
+
- Custom labels
|
|
16
|
+
- Field calculations
|
|
17
|
+
- Form validation
|
|
18
|
+
|
|
19
|
+
### Basic Syntax
|
|
20
|
+
```arcade
|
|
21
|
+
// Variables
|
|
22
|
+
var population = $feature.population;
|
|
23
|
+
var area = $feature.area_sqkm;
|
|
24
|
+
|
|
25
|
+
// Calculations
|
|
26
|
+
var density = population / area;
|
|
27
|
+
|
|
28
|
+
// Return result
|
|
29
|
+
return Round(density, 2);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Arcade in PopupTemplates
|
|
33
|
+
|
|
34
|
+
### Expression Infos
|
|
35
|
+
```javascript
|
|
36
|
+
const popupTemplate = {
|
|
37
|
+
title: "{name}",
|
|
38
|
+
expressionInfos: [
|
|
39
|
+
{
|
|
40
|
+
name: "population-density",
|
|
41
|
+
title: "Population Density",
|
|
42
|
+
expression: "Round($feature.population / $feature.area_sqkm, 2)"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "formatted-date",
|
|
46
|
+
title: "Formatted Date",
|
|
47
|
+
expression: "Text($feature.created_date, 'MMMM D, YYYY')"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
content: "Density: {expression/population-density} people/km²"
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Complex Expressions
|
|
55
|
+
```javascript
|
|
56
|
+
const popupTemplate = {
|
|
57
|
+
title: "{name}",
|
|
58
|
+
expressionInfos: [{
|
|
59
|
+
name: "predominant-category",
|
|
60
|
+
title: "Predominant Category",
|
|
61
|
+
expression: `
|
|
62
|
+
var fields = [
|
|
63
|
+
{ value: $feature.category_a, alias: "Category A" },
|
|
64
|
+
{ value: $feature.category_b, alias: "Category B" },
|
|
65
|
+
{ value: $feature.category_c, alias: "Category C" }
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
var maxValue = -Infinity;
|
|
69
|
+
var maxCategory = "";
|
|
70
|
+
|
|
71
|
+
for (var i in fields) {
|
|
72
|
+
if (fields[i].value > maxValue) {
|
|
73
|
+
maxValue = fields[i].value;
|
|
74
|
+
maxCategory = fields[i].alias;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return maxCategory;
|
|
79
|
+
`
|
|
80
|
+
}],
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: "text",
|
|
84
|
+
text: "The predominant category is: {expression/predominant-category}"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: "fields",
|
|
88
|
+
fieldInfos: [{
|
|
89
|
+
fieldName: "expression/predominant-category"
|
|
90
|
+
}]
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Arcade in Renderers
|
|
97
|
+
|
|
98
|
+
### Value Expression
|
|
99
|
+
```javascript
|
|
100
|
+
const renderer = {
|
|
101
|
+
type: "unique-value",
|
|
102
|
+
valueExpression: `
|
|
103
|
+
var labor = $feature.labor_force;
|
|
104
|
+
var notLabor = $feature.not_in_labor_force;
|
|
105
|
+
|
|
106
|
+
if (labor > notLabor) {
|
|
107
|
+
return "In labor force";
|
|
108
|
+
} else {
|
|
109
|
+
return "Not in labor force";
|
|
110
|
+
}
|
|
111
|
+
`,
|
|
112
|
+
valueExpressionTitle: "Labor Force Status",
|
|
113
|
+
uniqueValueInfos: [
|
|
114
|
+
{
|
|
115
|
+
value: "In labor force",
|
|
116
|
+
symbol: { type: "simple-fill", color: "blue" }
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
value: "Not in labor force",
|
|
120
|
+
symbol: { type: "simple-fill", color: "orange" }
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Visual Variable Expression
|
|
127
|
+
```javascript
|
|
128
|
+
const renderer = {
|
|
129
|
+
type: "simple",
|
|
130
|
+
symbol: { type: "simple-marker", color: "red" },
|
|
131
|
+
visualVariables: [{
|
|
132
|
+
type: "size",
|
|
133
|
+
valueExpression: "Sqrt($feature.population) * 0.1",
|
|
134
|
+
valueExpressionTitle: "Population (scaled)",
|
|
135
|
+
stops: [
|
|
136
|
+
{ value: 10, size: 4 },
|
|
137
|
+
{ value: 100, size: 40 }
|
|
138
|
+
]
|
|
139
|
+
}, {
|
|
140
|
+
type: "opacity",
|
|
141
|
+
valueExpression: "($feature.value / $feature.max_value) * 100",
|
|
142
|
+
valueExpressionTitle: "Percentage of max",
|
|
143
|
+
stops: [
|
|
144
|
+
{ value: 20, opacity: 0.2 },
|
|
145
|
+
{ value: 80, opacity: 1 }
|
|
146
|
+
]
|
|
147
|
+
}]
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Arcade in Labels
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
layer.labelingInfo = [{
|
|
155
|
+
symbol: {
|
|
156
|
+
type: "text",
|
|
157
|
+
color: "black",
|
|
158
|
+
font: { size: 10 }
|
|
159
|
+
},
|
|
160
|
+
labelExpressionInfo: {
|
|
161
|
+
expression: `
|
|
162
|
+
var name = $feature.name;
|
|
163
|
+
var pop = $feature.population;
|
|
164
|
+
|
|
165
|
+
if (pop > 1000000) {
|
|
166
|
+
return name + " (" + Round(pop/1000000, 1) + "M)";
|
|
167
|
+
} else if (pop > 1000) {
|
|
168
|
+
return name + " (" + Round(pop/1000, 0) + "K)";
|
|
169
|
+
}
|
|
170
|
+
return name;
|
|
171
|
+
`
|
|
172
|
+
},
|
|
173
|
+
where: "population > 50000"
|
|
174
|
+
}];
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Common Arcade Functions
|
|
178
|
+
|
|
179
|
+
### Math Functions
|
|
180
|
+
```arcade
|
|
181
|
+
Round(3.14159, 2) // 3.14
|
|
182
|
+
Floor(3.9) // 3
|
|
183
|
+
Ceil(3.1) // 4
|
|
184
|
+
Abs(-5) // 5
|
|
185
|
+
Sqrt(16) // 4
|
|
186
|
+
Pow(2, 3) // 8
|
|
187
|
+
Min(1, 2, 3) // 1
|
|
188
|
+
Max(1, 2, 3) // 3
|
|
189
|
+
Sum([1, 2, 3]) // 6
|
|
190
|
+
Mean([1, 2, 3]) // 2
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Text Functions
|
|
194
|
+
```arcade
|
|
195
|
+
Upper("hello") // "HELLO"
|
|
196
|
+
Lower("HELLO") // "hello"
|
|
197
|
+
Trim(" hello ") // "hello"
|
|
198
|
+
Left("hello", 2) // "he"
|
|
199
|
+
Right("hello", 2) // "lo"
|
|
200
|
+
Mid("hello", 2, 2) // "ll"
|
|
201
|
+
Find("l", "hello") // 2
|
|
202
|
+
Replace("hello", "l", "L") // "heLLo"
|
|
203
|
+
Split("a,b,c", ",") // ["a", "b", "c"]
|
|
204
|
+
Concatenate(["a", "b"]) // "ab"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Date Functions
|
|
208
|
+
```arcade
|
|
209
|
+
Now() // Current date/time
|
|
210
|
+
Today() // Current date
|
|
211
|
+
Year($feature.date_field) // Extract year
|
|
212
|
+
Month($feature.date_field) // Extract month (1-12)
|
|
213
|
+
Day($feature.date_field) // Extract day
|
|
214
|
+
DateDiff(Now(), $feature.date, "days") // Days between dates
|
|
215
|
+
Text($feature.date, "MMMM D, YYYY") // Format date
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Geometry Functions
|
|
219
|
+
```arcade
|
|
220
|
+
Area($feature, "square-kilometers")
|
|
221
|
+
Length($feature, "kilometers")
|
|
222
|
+
Centroid($feature)
|
|
223
|
+
Buffer($feature, 100, "meters")
|
|
224
|
+
Intersects($feature, $otherFeature)
|
|
225
|
+
Contains($feature, $point)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Conditional Functions
|
|
229
|
+
```arcade
|
|
230
|
+
// IIf (inline if)
|
|
231
|
+
IIf($feature.value > 100, "High", "Low")
|
|
232
|
+
|
|
233
|
+
// When (multiple conditions)
|
|
234
|
+
When(
|
|
235
|
+
$feature.type == "A", "Type A",
|
|
236
|
+
$feature.type == "B", "Type B",
|
|
237
|
+
"Other"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
// Decode (value matching)
|
|
241
|
+
Decode($feature.code,
|
|
242
|
+
1, "One",
|
|
243
|
+
2, "Two",
|
|
244
|
+
3, "Three",
|
|
245
|
+
"Unknown"
|
|
246
|
+
)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Array Functions
|
|
250
|
+
```arcade
|
|
251
|
+
var arr = [1, 2, 3, 4, 5];
|
|
252
|
+
|
|
253
|
+
Count(arr) // 5
|
|
254
|
+
First(arr) // 1
|
|
255
|
+
Last(arr) // 5
|
|
256
|
+
IndexOf(arr, 3) // 2
|
|
257
|
+
Includes(arr, 3) // true
|
|
258
|
+
Push(arr, 6) // [1, 2, 3, 4, 5, 6]
|
|
259
|
+
Reverse(arr) // [5, 4, 3, 2, 1]
|
|
260
|
+
Sort(arr) // [1, 2, 3, 4, 5]
|
|
261
|
+
Slice(arr, 1, 3) // [2, 3]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Feature Access
|
|
265
|
+
|
|
266
|
+
```arcade
|
|
267
|
+
// Current feature
|
|
268
|
+
$feature.fieldName
|
|
269
|
+
|
|
270
|
+
// All features in layer (for aggregation)
|
|
271
|
+
var allFeatures = FeatureSet($layer);
|
|
272
|
+
var filtered = Filter(allFeatures, "type = 'A'");
|
|
273
|
+
var total = Sum(filtered, "value");
|
|
274
|
+
|
|
275
|
+
// Related records
|
|
276
|
+
var related = FeatureSetByRelationshipName($feature, "relationshipName");
|
|
277
|
+
|
|
278
|
+
// Global variables
|
|
279
|
+
$map // Reference to map
|
|
280
|
+
$view // Reference to view
|
|
281
|
+
$datastore // Reference to data store
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Execute Arcade Programmatically
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
import Arcade from "@arcgis/core/arcade/Arcade.js";
|
|
288
|
+
|
|
289
|
+
// Create profile
|
|
290
|
+
const profile = {
|
|
291
|
+
variables: [{
|
|
292
|
+
name: "$feature",
|
|
293
|
+
type: "feature"
|
|
294
|
+
}]
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Compile expression
|
|
298
|
+
const executor = await Arcade.createArcadeExecutor(
|
|
299
|
+
"Round($feature.value * 100, 2)",
|
|
300
|
+
profile
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
// Execute with feature
|
|
304
|
+
const result = executor.execute({
|
|
305
|
+
$feature: graphic
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
console.log("Result:", result);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Arcade in HTML (Script Tags)
|
|
312
|
+
|
|
313
|
+
```html
|
|
314
|
+
<script type="text/plain" id="my-expression">
|
|
315
|
+
var total = $feature.value_a + $feature.value_b;
|
|
316
|
+
var percentage = Round((total / $feature.max_value) * 100, 1);
|
|
317
|
+
return percentage + "%";
|
|
318
|
+
</script>
|
|
319
|
+
|
|
320
|
+
<script type="module">
|
|
321
|
+
const expression = document.getElementById("my-expression").text;
|
|
322
|
+
|
|
323
|
+
const popupTemplate = {
|
|
324
|
+
expressionInfos: [{
|
|
325
|
+
name: "my-calc",
|
|
326
|
+
expression: expression
|
|
327
|
+
}],
|
|
328
|
+
content: "Value: {expression/my-calc}"
|
|
329
|
+
};
|
|
330
|
+
</script>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## TypeScript Usage
|
|
334
|
+
|
|
335
|
+
Arcade expression configurations use autocasting. For TypeScript safety, use `as const`:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Use 'as const' for expression-based visualizations
|
|
339
|
+
layer.renderer = {
|
|
340
|
+
type: "simple",
|
|
341
|
+
symbol: { type: "simple-marker" },
|
|
342
|
+
visualVariables: [{
|
|
343
|
+
type: "size",
|
|
344
|
+
valueExpression: "$feature.population / $feature.area",
|
|
345
|
+
stops: [
|
|
346
|
+
{ value: 50, size: 4 },
|
|
347
|
+
{ value: 500, size: 20 }
|
|
348
|
+
]
|
|
349
|
+
}]
|
|
350
|
+
} as const;
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
> **Tip:** See [arcgis-core-maps skill](../arcgis-core-maps/SKILL.md) for detailed guidance on autocasting vs explicit classes.
|
|
354
|
+
|
|
355
|
+
## Common Pitfalls
|
|
356
|
+
|
|
357
|
+
1. **Null values**: Check for nulls with `IsEmpty($feature.field)`
|
|
358
|
+
|
|
359
|
+
2. **Type coercion**: Use `Number()` or `Text()` for explicit conversion
|
|
360
|
+
|
|
361
|
+
3. **Case sensitivity**: Arcade is case-insensitive for functions but field names match exactly
|
|
362
|
+
|
|
363
|
+
4. **Performance**: Complex expressions in renderers can slow performance
|
|
364
|
+
|
|
365
|
+
5. **Debugging**: Use `Console()` function to debug expressions
|
|
366
|
+
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: arcgis-authentication
|
|
3
|
+
description: Implement authentication with ArcGIS using OAuth 2.0, API keys, and identity management. Use for accessing secured services, portal items, and user-specific content.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ArcGIS Authentication
|
|
7
|
+
|
|
8
|
+
Use this skill for implementing authentication, OAuth, API keys, and identity management.
|
|
9
|
+
|
|
10
|
+
## OAuth 2.0 Authentication
|
|
11
|
+
|
|
12
|
+
### Basic OAuth Setup
|
|
13
|
+
```javascript
|
|
14
|
+
import OAuthInfo from "@arcgis/core/identity/OAuthInfo.js";
|
|
15
|
+
import esriId from "@arcgis/core/identity/IdentityManager.js";
|
|
16
|
+
import Portal from "@arcgis/core/portal/Portal.js";
|
|
17
|
+
|
|
18
|
+
// Create OAuthInfo with your app ID
|
|
19
|
+
const oauthInfo = new OAuthInfo({
|
|
20
|
+
appId: "YOUR_APP_ID", // Register at developers.arcgis.com
|
|
21
|
+
popup: false // false = redirect, true = popup window
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Register with IdentityManager
|
|
25
|
+
esriId.registerOAuthInfos([oauthInfo]);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Check Sign-In Status
|
|
29
|
+
```javascript
|
|
30
|
+
async function checkSignIn() {
|
|
31
|
+
try {
|
|
32
|
+
await esriId.checkSignInStatus(oauthInfo.portalUrl + "/sharing");
|
|
33
|
+
// User is signed in
|
|
34
|
+
const portal = new Portal({ authMode: "immediate" });
|
|
35
|
+
await portal.load();
|
|
36
|
+
console.log("Signed in as:", portal.user.username);
|
|
37
|
+
return portal;
|
|
38
|
+
} catch {
|
|
39
|
+
// User is not signed in
|
|
40
|
+
console.log("Not signed in");
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Sign In
|
|
47
|
+
```javascript
|
|
48
|
+
async function signIn() {
|
|
49
|
+
try {
|
|
50
|
+
const credential = await esriId.getCredential(
|
|
51
|
+
oauthInfo.portalUrl + "/sharing"
|
|
52
|
+
);
|
|
53
|
+
console.log("Credential obtained:", credential);
|
|
54
|
+
return credential;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("Sign in failed:", error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Sign Out
|
|
62
|
+
```javascript
|
|
63
|
+
function signOut() {
|
|
64
|
+
esriId.destroyCredentials();
|
|
65
|
+
window.location.reload();
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Complete OAuth Flow
|
|
70
|
+
```javascript
|
|
71
|
+
import OAuthInfo from "@arcgis/core/identity/OAuthInfo.js";
|
|
72
|
+
import esriId from "@arcgis/core/identity/IdentityManager.js";
|
|
73
|
+
import Portal from "@arcgis/core/portal/Portal.js";
|
|
74
|
+
|
|
75
|
+
const oauthInfo = new OAuthInfo({
|
|
76
|
+
appId: "YOUR_APP_ID"
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
esriId.registerOAuthInfos([oauthInfo]);
|
|
80
|
+
|
|
81
|
+
// Check if already signed in
|
|
82
|
+
esriId.checkSignInStatus(oauthInfo.portalUrl + "/sharing")
|
|
83
|
+
.then(() => {
|
|
84
|
+
// Already signed in, load portal
|
|
85
|
+
const portal = new Portal({ authMode: "immediate" });
|
|
86
|
+
return portal.load();
|
|
87
|
+
})
|
|
88
|
+
.then((portal) => {
|
|
89
|
+
console.log("Welcome,", portal.user.fullName);
|
|
90
|
+
displayUserContent(portal);
|
|
91
|
+
})
|
|
92
|
+
.catch(() => {
|
|
93
|
+
// Not signed in, show sign-in button
|
|
94
|
+
showSignInButton();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
function showSignInButton() {
|
|
98
|
+
const btn = document.getElementById("signInBtn");
|
|
99
|
+
btn.onclick = () => {
|
|
100
|
+
esriId.getCredential(oauthInfo.portalUrl + "/sharing")
|
|
101
|
+
.then(() => {
|
|
102
|
+
window.location.reload();
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## OAuth Component
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<!-- Using OAuth component -->
|
|
112
|
+
<arcgis-oauth app-id="YOUR_APP_ID"></arcgis-oauth>
|
|
113
|
+
|
|
114
|
+
<script type="module">
|
|
115
|
+
const oauthComponent = document.querySelector("arcgis-oauth");
|
|
116
|
+
|
|
117
|
+
oauthComponent.addEventListener("arcgisSignIn", (event) => {
|
|
118
|
+
console.log("Signed in:", event.detail.credential);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
oauthComponent.addEventListener("arcgisSignOut", () => {
|
|
122
|
+
console.log("Signed out");
|
|
123
|
+
});
|
|
124
|
+
</script>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## API Keys
|
|
128
|
+
|
|
129
|
+
### Configure API Key
|
|
130
|
+
```javascript
|
|
131
|
+
import esriConfig from "@arcgis/core/config.js";
|
|
132
|
+
|
|
133
|
+
// Set API key for accessing services
|
|
134
|
+
esriConfig.apiKey = "YOUR_API_KEY";
|
|
135
|
+
|
|
136
|
+
// Now basemaps and services will use the API key
|
|
137
|
+
const map = new Map({
|
|
138
|
+
basemap: "arcgis/streets" // Requires API key
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### API Key in HTML
|
|
143
|
+
```html
|
|
144
|
+
<script>
|
|
145
|
+
// Set before loading the SDK
|
|
146
|
+
window.esriConfig = {
|
|
147
|
+
apiKey: "YOUR_API_KEY"
|
|
148
|
+
};
|
|
149
|
+
</script>
|
|
150
|
+
<script src="https://js.arcgis.com/4.34/"></script>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Enterprise Portal Authentication
|
|
154
|
+
|
|
155
|
+
### Configure for Enterprise Portal
|
|
156
|
+
```javascript
|
|
157
|
+
const oauthInfo = new OAuthInfo({
|
|
158
|
+
appId: "YOUR_APP_ID",
|
|
159
|
+
portalUrl: "https://your-portal.com/portal",
|
|
160
|
+
popup: true
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
esriId.registerOAuthInfos([oauthInfo]);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Set Portal URL Globally
|
|
167
|
+
```javascript
|
|
168
|
+
import esriConfig from "@arcgis/core/config.js";
|
|
169
|
+
|
|
170
|
+
esriConfig.portalUrl = "https://your-portal.com/portal";
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Token-Based Authentication
|
|
174
|
+
|
|
175
|
+
### Get Token Manually
|
|
176
|
+
```javascript
|
|
177
|
+
const credential = await esriId.getCredential("https://services.arcgis.com/...");
|
|
178
|
+
console.log("Token:", credential.token);
|
|
179
|
+
console.log("Expires:", new Date(credential.expires));
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Register Token
|
|
183
|
+
```javascript
|
|
184
|
+
esriId.registerToken({
|
|
185
|
+
server: "https://services.arcgis.com/",
|
|
186
|
+
token: "YOUR_TOKEN"
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Portal User Information
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
import Portal from "@arcgis/core/portal/Portal.js";
|
|
194
|
+
|
|
195
|
+
const portal = new Portal({ authMode: "immediate" });
|
|
196
|
+
await portal.load();
|
|
197
|
+
|
|
198
|
+
// User info
|
|
199
|
+
console.log("Username:", portal.user.username);
|
|
200
|
+
console.log("Full name:", portal.user.fullName);
|
|
201
|
+
console.log("Email:", portal.user.email);
|
|
202
|
+
console.log("Role:", portal.user.role);
|
|
203
|
+
console.log("Thumbnail:", portal.user.thumbnailUrl);
|
|
204
|
+
|
|
205
|
+
// Organization info
|
|
206
|
+
console.log("Org name:", portal.name);
|
|
207
|
+
console.log("Org ID:", portal.id);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Query User Items
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
import Portal from "@arcgis/core/portal/Portal.js";
|
|
214
|
+
import PortalQueryParams from "@arcgis/core/portal/PortalQueryParams.js";
|
|
215
|
+
|
|
216
|
+
const portal = new Portal({ authMode: "immediate" });
|
|
217
|
+
await portal.load();
|
|
218
|
+
|
|
219
|
+
// Query user's items
|
|
220
|
+
const queryParams = new PortalQueryParams({
|
|
221
|
+
query: `owner:${portal.user.username}`,
|
|
222
|
+
sortField: "modified",
|
|
223
|
+
sortOrder: "desc",
|
|
224
|
+
num: 20
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const result = await portal.queryItems(queryParams);
|
|
228
|
+
|
|
229
|
+
result.results.forEach(item => {
|
|
230
|
+
console.log(item.title, item.type, item.id);
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Credential Persistence
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
// Credentials are stored in localStorage by default
|
|
238
|
+
// Disable persistence
|
|
239
|
+
esriId.useSignInPage = false;
|
|
240
|
+
|
|
241
|
+
// Clear stored credentials
|
|
242
|
+
esriId.destroyCredentials();
|
|
243
|
+
|
|
244
|
+
// Check for stored credentials on load
|
|
245
|
+
const credentials = esriId.credentials;
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Handling Authentication Errors
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
// Global handler for authentication challenges
|
|
252
|
+
esriId.on("credential-create", (event) => {
|
|
253
|
+
console.log("New credential created:", event.credential);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Handle layer authentication errors
|
|
257
|
+
layer.on("layerview-create-error", (event) => {
|
|
258
|
+
if (event.error.name === "identity-manager:not-authorized") {
|
|
259
|
+
console.log("Authentication required for this layer");
|
|
260
|
+
signIn();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Trusted Servers
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
import esriConfig from "@arcgis/core/config.js";
|
|
269
|
+
|
|
270
|
+
// Add servers that should receive credentials automatically
|
|
271
|
+
esriConfig.request.trustedServers.push("https://services.arcgis.com");
|
|
272
|
+
esriConfig.request.trustedServers.push("https://your-server.com");
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## CORS and Proxy
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
import esriConfig from "@arcgis/core/config.js";
|
|
279
|
+
|
|
280
|
+
// Configure proxy for cross-origin requests
|
|
281
|
+
esriConfig.request.proxyUrl = "/proxy/";
|
|
282
|
+
|
|
283
|
+
// Configure proxy rules
|
|
284
|
+
esriConfig.request.proxyRules.push({
|
|
285
|
+
urlPrefix: "https://services.arcgis.com",
|
|
286
|
+
proxyUrl: "/proxy/"
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Common Pitfalls
|
|
291
|
+
|
|
292
|
+
1. **App ID registration**: App ID must be registered with correct redirect URIs
|
|
293
|
+
|
|
294
|
+
2. **Popup blockers**: OAuth popups may be blocked - use redirect flow as fallback
|
|
295
|
+
|
|
296
|
+
3. **Token expiration**: Tokens expire - handle refresh or re-authentication
|
|
297
|
+
|
|
298
|
+
4. **CORS errors**: Configure trusted servers or use proxy for cross-origin
|
|
299
|
+
|
|
300
|
+
5. **Portal URL mismatch**: Ensure portal URL matches exactly (trailing slashes matter)
|
|
301
|
+
|