UNPKG

@arcgis/coding-components

Version:

Contains components for editing code in different languages. The currently supported languages are html, css, json, TypeScript, JavaScript, and Arcade.

504 lines (503 loc) • 38.8 kB
import { c as V } from "../../chunks/runtime.js"; import { nothing as C, LitElement as L } from "@arcgis/lumina"; import { ref as B, createRef as j } from "lit/directives/ref.js"; import W from "@arcgis/core/identity/IdentityManager.js"; import { u as Q } from "../../chunks/useT9n.js"; import { b as E } from "../../chunks/arcade-defaults.js"; import { css as G } from "@lit/reactive-element/css-tag.js"; import { html as w } from "lit"; import T from "@arcgis/core/request.js"; import { e as J, a as Y } from "../../chunks/monaco-importer.js"; import { html as n } from "lit-html"; import { repeat as F } from "lit-html/directives/repeat.js"; import { generateGuid as K } from "@arcgis/components-utils"; import { unsafeHTML as k } from "lit/directives/unsafe-html.js"; import X from "@arcgis/core/layers/FeatureLayer.js"; import Z from "@arcgis/core/Graphic.js"; import { b as ee } from "../../chunks/language-defaults-base.js"; /*! All material copyright Esri, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.33/esri/copyright.txt for details. v4.33.14 */ const te = G`:host(:not([closed])){--calcite-block-border-color: var(--calcite-color-transparent);flex:1 0 auto;border-inline-start:var(--arcgis-coding-components-border);box-sizing:border-box;max-width:var(--arcgis-coding-components-side-panel-max-w);width:var(--arcgis-coding-components-side-panel-w);.submission-actions-wrapper{display:flex;flex-direction:column;width:100%;gap:.75rem}.submission-actions{display:flex;flex-direction:row;gap:.5rem;justify-content:space-between}.gaps{display:flex;gap:.25rem}.align-inline-end{margin-inline-start:auto}.action .error-display{display:flex;flex-direction:row;gap:.5rem;justify-content:space-between}.context-popover p{padding:0 .5rem;font-size:var(--calcite-font-size-sm)}.prompt-list calcite-list-item{margin-block-end:.5rem;border-radius:var(--calcite-corner-radius-round);--calcite-color-border-3: transparent;overflow:hidden}.feedback-content{padding:1rem;display:flex;flex-direction:column;gap:.75rem;max-height:30vh;overflow-y:auto}.feedback-sheet{--calcite-sheet-height: auto;--calcite-sheet-max-height: 100%;--calcite-sheet-min-height: auto}calcite-chip[slot=header-actions-end]{align-self:center;margin-inline-end:.5rem}calcite-list-item:focus calcite-button{position:relative;top:-2px}.prompt-list calcite-list-item:last-of-type{margin-block-end:0}calcite-list{--calcite-color-foreground-1: transparent;background-color:transparent}calcite-list-item{--calcite-color-foreground-1: white}calcite-flow-item calcite-shell{background:transparent}calcite-block{width:100%;max-width:100%;align-self:flex-end;background-color:transparent;margin-block:0}calcite-sheet{--calcite-sheet-scrim-background: rgba(200, 200, 200, .5)}.type-suggestion{--calcite-color-foreground-1: var(--calcite-color-foreground-current);--calcite-color-text-3: var(--calcite-color-text-2);--calcite-icon-color: var(--calcite-color-brand)}.type-history{--calcite-icon-color: var(--calcite-color-text-2)}.type-response{--calcite-icon-color: var(--calcite-color-brand);--calcite-font-family: monospace}.block-response{align-self:flex-start;margin-block-end:4rem;border-block-end:0;--calcite-block-text-color: var(--calcite-color-brand)}calcite-list-item calcite-button{margin-inline-end:.25rem}.type-docs{--calcite-color-foreground-1: var(--calcite-color-foreground-3);--calcite-icon-color: var(--calcite-color-text-1)}.type-error{--calcite-icon-color: var(--calcite-color-status-danger);--calcite-font-family: monospace;border:1px solid var(--calcite-color-status-danger)}#thumbs-up{margin-inline-start:auto;--calcite-icon-color: var(--calcite-color-border-input)}#thumbs-down{--calcite-icon-color: var(--calcite-color-border-input)}calcite-flow-item calcite-shell calcite-notice{margin-block:1rem}.no-space-block,.no-space-block[open]{margin:0}calcite-block[open]:last-of-type{border-block-end:0}.text-area-wrapper{display:flex;border-radius:var(--calcite-corner-radius-round);margin:.75rem;overflow:hidden;--calcite-color-border-input: transparent;position:sticky;box-shadow:var(--calcite-shadow-sm);flex:none}calcite-text-area{height:auto;min-height:5.75rem;overflow:hidden;border-radius:var(--calcite-corner-radius-round) var(--calcite-corner-radius-round) 0 0;--calcite-font-weight-normal: 500;font-weight:500;line-height:1.2}calcite-tooltip{--calcite-tooltip-z-index: 1000}.standalone-list{margin:1rem;width:calc(100% - 2rem)}.result-disclaimer{display:block;width:24rem;max-width:90%;margin:1rem auto;text-align:center;line-height:1.125rem;font-size:.875rem;font-style:italic}calcite-flow{height:100%}calcite-popover calcite-list{--calcite-list-background-color: transparent;--calcite-input-border-color: transparent}calcite-popover calcite-list calcite-filter{--calcite-spacing-sm: 0}.break-spaces{white-space:break-spaces}.feedback-button-container{margin-inline-start:auto;gap:0}.info-heading{font-size:var(--calcite-font-size-1);color:var(--calcite-color-text-1)}.unstyled-h3{margin:unset;font-size:var(--calcite-font-size-md)}.unstyled-shell{position:unset;inset:unset;display:unset;block-size:unset;inline-size:unset}.suggestion-button{font-weight:var(--calcite-font-weight-medium)}.info-block{max-width:450px}#result-block{calcite-card-group{--calcite-card-group-gap: 1.25rem}calcite-card{--calcite-card-corner-radius: var(--calcite-corner-radius-round);--calcite-card-background-color: white;--calcite-card-border-color: transparent;width:100%}.positioned-code-content{display:flex;flex-direction:row;gap:.5rem;padding:.5rem}calcite-card [slot=title] calcite-chip{margin-block-start:.25rem}.code-response-wrapper{position:relative;background:var(--calcite-color-foreground-2);border-radius:var(--calcite-corner-radius-round);margin-top:-1.5rem}.prior-prompt{display:flex;flex-direction:row;padding:0;overflow-y:hidden;overflow-x:auto;margin:.25rem 0 .75rem;align-items:center;max-width:100%;span{overflow-x:auto;overflow-y:hidden}}.copy-feedback{display:none}.copy-prompt-button{align-self:flex-start;margin-inline-start:auto}.response-secondary-action-button[data-copied]+.copy-feedback,.copy-prompt-button[data-copied]+.copy-feedback{display:block;span{padding:.75rem 1rem;font-size:var(--calcite-font-size--2);line-height:1.375;color:var(--calcite-color-text--2);font-weight:var(--calcite-font-weight-medium)}}.copy-prompt-button[data-copied]~.copy-tooltip,.response-secondary-action-button[data-copied]~.copy-tooltip{display:none}code{white-space:pre;font-size:12px;margin:0;overflow-x:auto;font-family:Fira Mono,Consolas,Menlo,monospace;display:block;max-height:12rem;position:relative;padding:.5rem}.code-collapse{margin-inline-start:auto}.response-secondary-action-button{margin-left:.5rem}.add-to-editor-button{--calcite-internal-button-border-color: unset}}.collapsible-code{padding:.5rem}.collapsible-code summary{cursor:pointer;font-weight:500;color:var(--calcite-color-brand);outline:none;padding:.25rem 0}.collapsible-code[open] summary{color:var(--calcite-color-text-2)}.collapsible-error{padding:.5rem}.collapsible-error summary{cursor:pointer;font-weight:500;color:var(--calcite-color-status-danger);outline:none;padding:.25rem 0}.collapsible-error[open] summary{color:var(--calcite-color-text-2)}.response-error-container{padding:.5rem;background:color-mix(in srgb,var(--calcite-color-status-warning) 10%,transparent);border-radius:var(--calcite-corner-radius-round);margin:1rem 0;font-size:var(--calcite-font-size--2);--calcite-input-message-icon-color: var(--calcite-color-status-warning)}.response-error-chip{--calcite-internal-chip-background-color: var(--calcite-color-status-warning);--calcite-chip-icon-color: var(--calcite-color-foreground-1);--calcite-chip-border-color: var(--calcite-color-transparent)}.feedback-actions{gap:unset}}:host([closed]){display:none}`; class $ extends Error { constructor({ message: e, code: t, subCode: o, details: r, source: c }) { super(e), this.name = "ArcadeAssistantError", this.code = t, this.subCode = o, this.details = r, this.source = c; } } function P(i) { if (!i) return; const e = i.indexOf('{"error":'); if (e !== -1) try { const t = i.slice(e), o = JSON.parse(t); if (o && typeof o == "object" && o.error) return o.error; } catch { return; } } async function ie(i) { const { baseUrl: e, skillId: t, message: o, authToken: r, previousConversationId: c, context: h } = i, d = t ? `${e}/skills/${t}/chat` : `${e}/chat`, s = [], m = { message: o, context: h }; c && (m.conversation_id = c); let a; try { a = await T(d, { method: "post", headers: { "Content-Type": "application/json", token: r }, body: JSON.stringify(m), responseType: "json" }); } catch (b) { const g = b, x = g.details?.rawResponse || g.message || String(b), y = P(x); throw y ? new $(y) : b; } const l = a.data; s.push(l); const p = l.conversationId, _ = l.inquiryId; let S = l.sequenceNumber; async function z() { let b = 0; const g = 25; for (; b < g; ) { await new Promise((v) => setTimeout(v, 1e3)); const x = oe(p, S, _); let y; try { y = await T(d, { method: "post", headers: { "Content-Type": "application/json", token: r }, body: JSON.stringify(x), responseType: "json" }); } catch (v) { const R = v, H = R.details?.rawResponse || R.message || String(v), I = P(H); throw I ? new $(I) : v; } const f = y.data; if (f.context && f.context.kind === "ArcgisErrorAsContext" && f.context.error) throw new $({ message: f.context.error.message || "ArcGIS Assistant error", code: f.context.error.code, subCode: f.context.error.subCode, details: f.context.error.details, source: "polling-response" }); if (s.push(f), S = f.sequenceNumber, b++, !f.hasMore) break; } if (b === g) throw new $({ message: "Request timed out", code: "TIMEOUT", source: "polling" }); } const O = 2 * 60 * 1e3; return await Promise.race([ z(), new Promise( (b, g) => setTimeout( () => g( new $({ message: "Request timed out", code: "TIMEOUT", source: "hard-timeout" }) ), O ) ) ]), s; } function oe(i, e, t) { return { conversationId: i, inquiryId: t, ackSequenceNumber: e }; } function ae(i) { return i.message.match(/Error in prompt shield/u) ? "I'm having trouble with this request. Try again by rephrasing the question." : i.code === "TIMEOUT" ? "I'm having trouble with this request. Try again by re-asking the same question or rephrasing it." : i.message; } const se = (i) => { const e = i.value.length, t = 72, o = 180, r = i.offsetWidth, h = Math.max(1, Math.floor(r / 8)), d = Math.ceil(e / h), s = t + (d - 2) * 24; i.style.setProperty("--calcite-text-area-min-height", `${Math.min(s, o)}px`); }; function re({ messages: i }) { return n`<calcite-chip slot=header-actions-end scale=s appearance=outline-fill .label=${i.beta ?? "Beta"}>${i.beta ?? "Beta"}</calcite-chip>`; } function ce({ popoverContent: i }) { return n`<calcite-action icon=information slot=header-actions-end id=legal-disclaimer text></calcite-action><calcite-popover reference-element=legal-disclaimer overlay-positioning=fixed label=legal-disclaimer placement=bottom auto-close>${i}</calcite-popover>`; } function D({ errorMessage: i, slot: e }) { return n`<div class="error-display"><calcite-input-message id=error-message status=invalid icon=exclamation-mark-triangle scale=m slot=${e ?? C}>${i}</calcite-input-message></div>`; } function ne({ active: i, setActive: e, messages: t }) { return n`<calcite-alert slot=alerts .open=${i} placement=bottom kind=success icon=check-circle-f auto-close @calciteAlertClose=${() => e(!1)} .label=${t.expressionapplied ?? "Expression applied"}><div slot=message>${t.expressionapplied ?? "Expression applied to editor."}</div></calcite-alert>`; } function le({ context: i, messages: e }) { return i ? n`<div class="gaps">${i.profileName && n`<calcite-popover auto-close placement=top .label=${e.profilecontextlabel.replace("{profileName}", i.profileName)} reference-element=profile-context-button class="context-popover"><p>${e.profilecontextlabel.replace("{profileName}", i.profileName)}</p></calcite-popover><calcite-button round kind=neutral icon-start=map-information id=profile-context-button></calcite-button>` || ""}${i.layerName && n`<calcite-popover auto-close placement=top .label=${e.layercontextlabel.replace("{layerName}", i.layerName)} reference-element=layer-context-button class="context-popover"><p>${e.layercontextlabel.replace("{layerName}", i.layerName)}</p></calcite-popover><calcite-button round kind=neutral icon-start=layers id=layer-context-button></calcite-button>` || ""}</div>` : null; } function de({ isDisabled: i, isReadOnly: e, setQuestion: t, setIsViewingResult: o, textAreaRef: r, question: c, errorMessage: h, setErrorMessage: d, submitQuestion: s, messages: m, mode: a, context: l }) { return n`<div class="text-area-wrapper"><calcite-text-area resize=vertical .readOnly=${i || e} class="styled-text-area" .placeholder=${m.askaquestion ?? `Specify the calculation or logic you need in an Arcade expression. (e.g., 'Return "Yes" if value > 10')`} .value=${c} @calciteTextAreaInput=${(p) => { se(p.target), t(p.target.value); }} ${B(r)}><div class="submission-actions-wrapper" slot=footer-start>${h && D({ errorMessage: h, slot: "footer-start" }) || ""}<div class="submission-actions">${le({ context: l, messages: m })}<div class="align-inline-end gaps"><calcite-button round kind=neutral .hidden=${a !== "refine"} icon-start=arrow-left icon-flip-rtl=both appearance=solid .disabled=${i} @click=${async () => { o(!1), t(""); }}>${m.startover ?? "Start Over"}</calcite-button><calcite-button round icon-end=effects appearance=solid .loading=${i} .disabled=${i} @click=${async () => { d(c ? "" : m.enteraprompt ?? "Please enter a prompt"), await s(); }}>${a === "prompt" ? m.ask ?? "Generate" : m.refine ?? "Refine"}</calcite-button></div></div></div></calcite-text-area></div>`; } const pe = "https://www.esri.com/en-us/privacy/privacy-statements/privacy-statement", ue = "https://www.esri.com/en-us/privacy/privacy-statements/privacy-supplement"; function he({ setOpen: i, messages: e, feedback: t, setFeedback: o, onSubmit: r }) { return t.active ? n`<calcite-sheet class="feedback-sheet" .label=${e.feedback ?? "Feedback"} slot=sheets display-mode=float position=block-end .open=${t.active} @calciteSheetClose=${() => i(!1)}><calcite-panel .heading=${e.providefeedback ?? "Provide feedback"} .description=${e.experiencehelps ?? "Your experience helps guide future improvements"}><div class="feedback-content"><calcite-label>${e.experiencehelpful ?? "Was the assistant helpful?"}<calcite-segmented-control scale=l><calcite-segmented-control-item icon-start=thumbs-up .checked=${t.value === "good"} @click=${() => o({ ...t, value: "good" })}></calcite-segmented-control-item><calcite-segmented-control-item icon-start=thumbs-down .checked=${t.value === "bad"} @click=${() => o({ ...t, value: "bad" })}></calcite-segmented-control-item></calcite-segmented-control></calcite-label><calcite-label>${e.describeexperience ?? "Describe your experience"}<calcite-text-area resize=vertical .value=${t.text} @calciteTextAreaInput=${(c) => o({ ...t, text: c.target.value })}></calcite-text-area></calcite-label><calcite-label layout=inline scale=s><calcite-checkbox scale=l .checked=${t.termsAccepted} @calciteCheckboxChange=${(c) => { o({ ...t, termsAccepted: c.target.checked }); }}></calcite-checkbox><span>${k(e.agreement?.replace("{EsriPrivacyStatement}", `<calcite-link href=${pe} target="_blank">${e.esriprivacystatement ?? "Esri Privacy Statement"}</calcite-link>`).replace("{Supplement}", `<calcite-link href=${ue} target="_blank">${e.supplement ?? "Supplement"}</calcite-link>`))}</span></calcite-label></div><calcite-button slot=footer width=full @click=${r} .disabled=${!t.termsAccepted || t.submitting} .loading=${t.submitting}>${e.submitfeedback ?? "Submit Feedback"}</calcite-button></calcite-panel></calcite-sheet>` : null; } function q({ assistantsEnabled: i, messages: e, slot: t, assistantHelpUrl: o, helpTopicUrl: r }) { return n`<calcite-block .label=${e.assistantinformation ?? "Assistant information"} slot=${t ?? C} expanded class="info-block"><calcite-chip .label=${e.new ?? "new"} kind=brand>${e.new}</calcite-chip><h1 class="info-heading">${e.introducing}</h1><p>${e.capabilities}</p>${i ? n`<p>${e.keepinmind ?? "Keep in mind the following:"}<ul><li>${e.beconsise ?? "Be concise, but also clear in your request"}</li><li>${e.avoidambiguity ?? "Avoid ambiguity and vagueness"}</li><li>${e.moredetails ?? "you do not need to use exact field names in your instructions, but more detail is generally better"}</li></ul>${k((e.seedocumentation ?? "Please see the {documentation} for more information, including limitations and additional resources.").replace("{documentation}", `<calcite-link href=${r} target="_blank">${e.documentation ?? "documentation"}</calcite-link>`))}</p>` : n`<p>${k(e.useofassistant?.replace("{aiassistants}", `<strong>${e.aiassistants ?? "Ai Assistants"}</strong>`))}<calcite-link .href=${o} target=_blank icon-end=launch-2>${e.opensettings ?? "Open Settings"}</calcite-link></p>`}</calcite-block>`; } function me({ messages: i, onProceed: e, onExit: t, helpTopicUrl: o }) { return n`<calcite-dialog close-disabled placement=top .heading=${i.welcome} slot=dialogs open width-scale=m id=welcome-dialog><h3 class="unstyled-h3">${i.beforeyougetstarted}</h3><ul><li>${i.maybeincorrect}</li><li>${k(i.pleasereadhelp.replace("{helpTopic}", `<calcite-link href=${o} target="_blank">${i.helptopic}</calcite-link>`))}</li></ul><calcite-button id=welcome-proceed slot=footer-end @click=${e}>${i.proceed}</calcite-button><calcite-button id=welcome-decline slot=footer-start @click=${t} kind=neutral>${i.exit}</calcite-button></calcite-dialog>`; } function fe({ messages: i, suggestions: e, onSuggestionClick: t }) { return n`<calcite-block .heading=${i.promptsuggestions} expanded collapsible id=suggestion-block><calcite-chip-group class="suggestions" .label=${i.promptsuggestions ?? "Prompt Suggestions"}>${F(e, (o) => o, (o) => n`<calcite-button round appearance=outline-fill kind=neutral .label=${i.promptsuggestion} class="suggestion-button" @click=${() => t?.(o)}>${o}</calcite-button>`)}</calcite-chip-group></calcite-block>`; } function M({ hidden: i = !1, expanded: e = !1, messages: t, cards: o, heading: r, collapsible: c = !1, showEffectsIcon: h = !1, onCopyCode: d, standalone: s }) { const m = t.addtoeditor ?? "Add to editor"; return n`<calcite-block .hidden=${i} id=result-block .heading=${r ?? t.besteffort ?? "Here is the assistant's best effort"} .expanded=${e} .collapsible=${c}>${h && n`<calcite-chip .label=${t.assistantresponses} slot=content-start icon=effects scale=m class="suggestion-chips"></calcite-chip>` || ""}<calcite-card-group .label=${t.assistantresponses}>${F(o, (a) => a.conversationId, (a) => n`<calcite-card><div slot=heading><div class="prior-prompt"><span>${a.priorPrompt}</span><calcite-action icon=duplicate scale=s slot=actions-end class="copy-prompt-button" text .id=${`copy-prompt-${a.conversationId}-${s ? "standalone" : "list"}`} @click=${(l) => { const p = l.currentTarget; navigator.clipboard.writeText(a.priorPrompt).then(() => { p.setAttribute("data-copied", "true"), setTimeout(() => p.removeAttribute("data-copied"), 1500); }); }}></calcite-action><calcite-popover .referenceElement=${`copy-prompt-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start class="copy-feedback" .label=${t.copiedsuccessfully ?? "copied successfully"} open trigger-disabled><span>${t.copiedsuccessfully ?? "copied successfully"}</span></calcite-popover><calcite-tooltip .referenceElement=${`copy-prompt-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start class="copy-tooltip">${t.copyprompttoclipboard}</calcite-tooltip></div>${a.message && s && n`<div class="response-error-container">${D({ errorMessage: a.message })}</div>` || ""}</div><div><div class="code-response-wrapper"><div class="positioned-code-content"><calcite-chip-group .label=${t.responsecontext ?? "Response Context"} scale=s>${a.message && !s && n`<calcite-tooltip .referenceElement=${`response-chip-${a.conversationId}-error`} placement=top-start overlay-positioning=fixed>${a.message}</calcite-tooltip><calcite-chip .id=${`response-chip-${a.conversationId}-error`} .label=${t.error ?? "Error"} scale=s appearance=outline icon=exclamation-mark-triangle-f class="response-error-chip"></calcite-chip>` || ""}${a.chips?.map((l) => { const p = K(); return n`${l.tooltip && n`<calcite-tooltip .referenceElement=${`response-chip-${l.conversationId}-${p}`} placement=top-start overlay-positioning=fixed>${l.tooltip}</calcite-tooltip>` || ""}<calcite-chip .label=${l.label} .scale=${l.scale ?? "s"} .appearance=${l.appearance ?? "outline"} .icon=${l.icon} .id=${`response-chip-${l.conversationId}-${p}`}>${l.label}</calcite-chip>`; })}</calcite-chip-group></div><details class="collapsible-code" open><summary>Code response</summary><code>${a.code}</code></details></div></div><div slot=footer-start class="feedback-actions"><calcite-button primary-text=${m ?? C} class="add-to-editor-button" @click=${() => a.onAddToEditor("add")} overlay-positioning=fixed scale=s icon-start=plus round>${t.addtoeditor ?? "Add to editor"}</calcite-button><calcite-button round icon-start=file-code kind=neutral scale=s @click=${() => a.onAddToEditor("replace")} class="response-secondary-action-button" .id=${`replace-${a.conversationId}-${s ? "standalone" : "list"}`}></calcite-button><calcite-tooltip .referenceElement=${`replace-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start><span>${t.replaceineditor ?? "Replace all code in editor"}</span></calcite-tooltip><calcite-button round icon-start=copy-to-clipboard kind=neutral scale=s @click=${(l) => { const p = l.currentTarget; d(a.code).then(() => { p.setAttribute("data-copied", "true"), setTimeout(() => p.removeAttribute("data-copied"), 1500); }); }} class="response-secondary-action-button" .id=${`copy-response-${a.conversationId}-${s ? "standalone" : "list"}`}></calcite-button><calcite-popover .referenceElement=${`copy-response-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start class="copy-feedback" .label=${t.copiedsuccessfully ?? "copied successfully"} open trigger-disabled><span>${t.copiedsuccessfully ?? "copied successfully"}</span></calcite-popover><calcite-tooltip .referenceElement=${`copy-response-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start class="copy-tooltip">${t.copytoclipboard}</calcite-tooltip></div><div slot=footer-end class="feedback-actions"><calcite-action .text=${t.thumbsup} scale=s icon=thumbs-up @click=${a.onThumbsUp} .id=${`thumbs-up-${a.conversationId}-${s ? "standalone" : "list"}`}></calcite-action><calcite-tooltip .referenceElement=${`thumbs-up-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start><span>${t.helpful ?? "Helpful"}</span></calcite-tooltip><calcite-action .text=${t.thumbsdown} scale=s icon=thumbs-down @click=${a.onThumbsDown} .id=${`thumbs-down-${a.conversationId}-${s ? "standalone" : "list"}`}></calcite-action><calcite-tooltip .referenceElement=${`thumbs-down-${a.conversationId}-${s ? "standalone" : "list"}`} placement=top-start><span>${t.unhelpful ?? "Unhelpful"}</span></calcite-tooltip></div></calcite-card>`)}</calcite-card-group></calcite-block>`; } const u = { welcome: "Welcome to the new assistant experience", beforeyougetstarted: "Before you get started be aware:", maybeincorrect: "AI generated code may occasionally be incorrect or biased. Review carefully.", pleasereadhelp: "Read the Arcade Assistant (beta) {helpTopic} to get started and learn details on security, privacy and limitations.", proceed: "Proceed", exit: "Exit", promptsuggestions: "Prompt suggestions", promptsuggestion: "Prompt suggestion", assistantresponses: "Assistant responses", collapse: "Collapse", thumbsup: "Thumbs up", thumbsdown: "Thumbs down", refine: "Refine", startover: "Start over", helptopic: "help topic", agreement: "I agree to the {EsriPrivacyStatement} (and {Supplement}).", esriprivacystatement: "Esri Privacy Statement", supplement: "Supplement", disclaimerpt2: "AI-generated content may be inaccurate. Review before using.", replaceineditor: "Replace all code in editor", keepinmind: "Keep in mind the following:", beconsise: "Be concise, but also clear in your request", avoidambiguity: "Avoid ambiguity and vagueness", documentation: "documentation", useexamples: "Use examples to clarify your request", moredetails: "You do not need to use exact field names in your instructions, but more detail is generally better", seedocumentation: "Please see the {documentation} for more information, including limitations and additional resources.", assistantinformation: "Assistant information", profilecontextlabel: "Profile context: {profileName}", layercontextlabel: "Layer context: {layerName}", numlayers: "{numLayers} {layerOrLayers}", numlayersplural: "layers", numlayerssingular: "layer", responsecontext: "Response context", error: "Error", copytoclipboard: "Copy code to clipboard", copyprompttoclipboard: "Copy prompt to clipboard", copiedsuccessfully: "Copied successfully", helpful: "Helpful", unhelpful: "Unhelpful" }, be = "arcade_generation", ge = "ArcadeCodeRequest", A = "visualization", ye = "ArcadeAssistant", ve = [ "your_comments", "user_evaluation", "question", "answer", "useragent", "_source", "version", "context", "extras" ]; let U = [], N = !0; class $e extends L { constructor() { super(...arguments), this.textAreaRef = j(), this.messages = Q(), this._feedbackService = void 0, this.handleFeedbackButton = (e, t) => { this.feedback = { active: !0, value: e, item: t, termsAccepted: !1, text: "", submitting: !1 }; }, this.handleFeedbackSheetClose = () => { this.feedback = { active: !1 }; }, this.handleFeedbackSubmit = async () => { if (!this.feedback.active) return; this.feedback = { ...this.feedback, submitting: !0 }; const e = await this.ensureFeedbackService(); if (!e) { this.handleFeedbackSheetClose(); return; } const t = this.getModel(), o = t ? await this.getProfileAndMetadata(t.uri) : void 0, r = { user_evaluation: this.feedback.value, your_comments: this.feedback.text || void 0, question: this.feedback.item?.question ?? "", /** * The answer may contain invalid or partial HTML, which causes the feature service's HTML sanitizer to strip or reject it. * To preserve the content reliably, we encode it using encodeURIComponent, which escapes all non-ASCII and special characters. * This ensures the content passes through the sanitizer safely and can be decoded later. This is a temporary workaround until * the sanitizer can be disabled on the service. */ answer: encodeURIComponent(this.feedback.item?.formattedScript ?? ""), useragent: navigator.userAgent, _source: ye, version: this.appVersion ?? "", context: o ? JSON.stringify(o) : "", extras: o?.profileName ?? "", conversation_id: this.feedback.item?.conversationId ?? "", privacy_statement: this.feedback.termsAccepted ? "I_agree" : "" }; try { await e.applyEdits({ addFeatures: [new Z({ attributes: r })] }); } catch (c) { console.error("Error submitting feedback:", c); } this.handleFeedbackSheetClose(); }, this.handleClose = (e) => { this.closed = !0, this.closePanel?.(e); }, this.setQuestion = (e) => { this.question = e; }, this.onSuggestionClick = (e) => { this.textAreaRef.value && (this.textAreaRef.value.value = e, this.textAreaRef.value.setFocus(), this.setQuestion(e)); }, this.isViewingResult = !1, this.confirmationActive = !1, this.isSubmitting = !1, this.errorMessage = void 0, this.question = "", this.history = [], this.feedback = { active: !1 }, this.splashActive = !0, this.context = void 0, this.historyCards = [], this.helpBase = "", this.assistantsEnabled = !1, this.closed = !1; } static { this.properties = { isViewingResult: 16, confirmationActive: 16, isSubmitting: 16, errorMessage: 16, question: 16, history: 16, feedback: 16, splashActive: 16, context: 16, historyCards: 16, closePanel: 0, insertText: 0, helpBase: 1, assistantsEnabled: 5, layer: [1, { type: Object }], portalUrl: 1, serviceUrl: 1, closed: 7, editorRef: 0, feedbackServiceUrl: 1, appVersion: 1 }; } static { this.styles = te; } get disclaimerComment() { return `// ${this.messages.disclaimercomment} // ${u.disclaimerpt2}`; } get assistantHelpUrl() { return `${this.helpBase ?? "https://doc.arcgis.com/en/arcgis-online/"}administer/configure-assistants.htm`; } get assistantOverviewDocUrl() { return `${this.helpBase ?? "https://doc.arcgis.com/en/arcgis-online/"}create-maps/understand-arcade-assistant.htm`; } get usingTheAssitantDocUrl() { return `${this.helpBase ?? "https://doc.arcgis.com/en/arcgis-online/"}create-maps/use-arcade-assistant.htm`; } async destroy() { } load() { const e = async () => { const t = this.getModel(); if (!t) { this.context = void 0; return; } const o = await this.getProfileAndMetadata(t.uri); this.context = o; }; e().catch((t) => { console.error("Error setting initial context in Arcade Assistant:", t); }), this.manager.onLifecycle(() => ({ remove: E.onModelContextDidChange(async () => { e().catch((o) => { console.error("Error setting context in Arcade Assistant:", o); }); }).dispose })); } willUpdate(e) { e.has("history") && (this.historyCards = this.getHistoryCards()); } connectedCallback() { super.connectedCallback(), this.history = U, this.splashActive = N; } disconnectedCallback() { super.disconnectedCallback(), U = this.history, N = this.splashActive, this.copySuccessTimer && (clearTimeout(this.copySuccessTimer), this.copySuccessTimer = void 0); } getHistoryCards() { return this.history.reduce((e, t) => (!t.script || (e.push({ priorPrompt: t.question, code: t.formattedScript || t.error || "", chips: [ { label: t.profile ?? A, icon: "map-information", appearance: "outline", scale: "s", conversationId: t.conversationId ?? "", tooltip: u.profilecontextlabel.replace("{profileName}", t.profile ?? A) }, ...t.layerName ? [ { label: u.numlayers.replace("{numLayers}", "1").replace("{layerOrLayers}", u.numlayerssingular), icon: "layer", appearance: "outline", scale: "s", conversationId: t.conversationId ?? "", tooltip: u.layercontextlabel.replace("{layerName}", t.layerName ?? "No layer") } ] : [] ], onAddToEditor: (o) => { J(this.editorRef.editorInstance, t.formattedScript ?? "", o, this.disclaimerComment); }, onThumbsUp: () => this.handleFeedbackButton("good", t), onThumbsDown: () => this.handleFeedbackButton("bad", t), conversationId: t.conversationId ?? "", message: t.message }), this.isViewingResult), e), []); } setFeedbackState(e) { this.feedback = e; } async ensureFeedbackService() { if (this._feedbackService) return this._feedbackService; if (!this.feedbackServiceUrl) return; const e = new X({ url: this.feedbackServiceUrl }); await e.load(); const t = ve.filter((o) => !e.fields.some((r) => r.name === o)); if (t.length > 0) { console.error(`Missing the following fields in feedback service: ${t.join(", ")}. Feedback will not be logged.`); return; } return this._feedbackService = e, e; } getModel() { return this.editorRef.editorInstance?.getModel(); } async submitQuestion() { if (this.question) { this.isSubmitting = !0; try { const e = await this.getToken(), t = this.getModel(); if (!t) return; const { profileName: o, metadata: r, layerName: c } = await this.getProfileAndMetadata(t.uri), d = (await ie({ baseUrl: this.serviceUrl, skillId: be, message: this.question, authToken: e, context: { kind: ge, context: { profile_name: o, metadata: r } } })).find((s) => s.context?.kind === "ArcadeCodeResponse"); if (!d) return; d.context?.kind === "ArcadeCodeResponse" && (this.history = [ { script: d?.context?.arcadeCode?.code, formattedScript: Y(d?.context?.arcadeCode?.code ?? ""), error: void 0, question: this.question, profile: o, conversationId: d.conversationId, layerName: c ?? void 0, ...d.message ? { message: d.message } : {} }, ...this.history ], this.isViewingResult = !0, this.errorMessage = void 0); } catch (e) { e instanceof Error && e.name === "ArcadeAssistantError" ? this.errorMessage = ae(e) || this.messages.erroroccurred || "An error occurred." : this.errorMessage = this.messages.erroroccurred || "An error occurred.", console.error("Error in Arcade Assistant:", e); } finally { this.isSubmitting = !1; } } } async getToken() { const { token: e } = await W.getCredential(this.portalUrl); return e; } async getProfileAndMetadata(e) { let t = A; const o = E.getEditorProfileForModel(e); o?.loaded || await o?.loadSource(); const r = this.editorRef.profile; r && "id" in r && (t = r.id); const c = o?.definition?.variables?.find((s) => s.type === "feature"); let h = [], d; return c?.definition && "fields" in c.definition && (h = c.definition.fields.map((s) => ({ name: s.name, type: s.type, alias: s.alias })), ee(c?.definition) && (d = c.definition.title)), { profileName: t, metadata: h, layerName: d }; } onCopyCode(e) { const t = e ? `${this.disclaimerComment} ${e}` : ""; return navigator.clipboard.writeText(t); } render() { return this.closed ? null : this.assistantsEnabled ? w`<calcite-flow><calcite-flow-item closable .heading=${this.messages.arcadeassistant ?? "Arcade assistant"} @calciteFlowItemClose=${this.handleClose}>${this.splashActive && w`<calcite-scrim></calcite-scrim>` || ""}${re({ messages: this.messages })}${ce({ popoverContent: q({ assistantsEnabled: this.assistantsEnabled, messages: { ...this.messages, ...u }, assistantHelpUrl: this.assistantHelpUrl, helpTopicUrl: this.usingTheAssitantDocUrl }) })}<calcite-shell class="unstyled-shell">${this.splashActive && me({ messages: { ...u, ...this.messages }, onProceed: () => { this.splashActive = !1; }, helpTopicUrl: this.assistantOverviewDocUrl, onExit: (e) => this.closePanel && this.closePanel(e) }) || ""}${ne({ active: this.confirmationActive, setActive: (e) => this.confirmationActive = e, messages: this.messages })}${de({ isDisabled: this.isSubmitting, isReadOnly: !1, setQuestion: this.setQuestion, setIsViewingResult: (e) => this.isViewingResult = e, mode: this.isViewingResult ? "refine" : "prompt", textAreaRef: this.textAreaRef, question: this.question, errorMessage: this.errorMessage, setErrorMessage: (e) => this.errorMessage = e, submitQuestion: this.submitQuestion.bind(this), messages: { ...u, ...this.messages }, context: this.context })}<calcite-block-group label="interactive blocks">${!this.isViewingResult && !this.isSubmitting && fe({ messages: { ...this.messages, ...u }, suggestions: ["Round value to one decimal place", 'Return "Yes" if value > 10'], onSuggestionClick: this.onSuggestionClick }) || ""}<calcite-block .hidden=${!this.isSubmitting} .heading=${this.messages.generatingresponse ?? "Generating response..."}></calcite-block>${M({ expanded: this.isViewingResult, messages: { ...this.messages, ...u }, collapsible: !0, showEffectsIcon: !0, /** Only show the latest history card */ cards: this.historyCards.length ? [this.historyCards[0]] : [], heading: this.messages.besteffort ?? "Here's the assistant's best effort", hidden: this.isSubmitting || !this.isViewingResult, onCopyCode: this.onCopyCode.bind(this), standalone: !0 })}${M({ expanded: !this.isViewingResult, messages: { ...this.messages, ...u }, collapsible: !0, /** * When the user is viewing the latest result, we display the first history card * (historyCards[0]) separately at the top in "standalone" mode. * To avoid showing the same card twice, we remove (slice out) the first card * from the list of recent prompts below. */ cards: this.isViewingResult ? this.historyCards.slice(1) : this.historyCards, heading: this.messages.recentprompts ?? "Recent prompts", hidden: this.isSubmitting || this.history.length === 0, onCopyCode: this.onCopyCode.bind(this) })}</calcite-block-group>${this.feedback.active ? he({ setOpen: this.handleFeedbackSheetClose, messages: { ...this.messages, ...u }, onSubmit: this.handleFeedbackSubmit, feedback: this.feedback, setFeedback: this.setFeedbackState.bind(this) }) : null}</calcite-shell></calcite-flow-item></calcite-flow>` : w`<calcite-flow><calcite-flow-item .selected=${!this.isViewingResult} closable .heading=${this.messages.arcadeassistant ?? "Arcade assistant"} @calciteFlowItemClose=${this.handleClose}>${q({ slot: "content-top", messages: { ...this.messages, ...u }, assistantsEnabled: this.assistantsEnabled, assistantHelpUrl: this.assistantHelpUrl, helpTopicUrl: this.usingTheAssitantDocUrl })}</calcite-flow-item></calcite-flow>`; } } V("arcgis-arcade-coding-assistant", $e); export { $e as ArcgisArcadeCodingAssistant };