diff --git a/packages/api/.env b/packages/api/.env index d07e42182..8b55cc452 100644 --- a/packages/api/.env +++ b/packages/api/.env @@ -2,6 +2,8 @@ DEVMODE=1 SHELL_SCRIPTING=1 ALLOW_DBGATE_PRIVATE_CLOUD=1 DEVWEB=1 +# LOCAL_AI_GATEWAY=true + # REDIRECT_TO_DBGATE_CLOUD_LOGIN=1 # PROD_DBGATE_CLOUD=1 # PROD_DBGATE_IDENTITY=1 diff --git a/packages/api/src/controllers/cloud.js b/packages/api/src/controllers/cloud.js index 8dae42c00..61a3a9003 100644 --- a/packages/api/src/controllers/cloud.js +++ b/packages/api/src/controllers/cloud.js @@ -16,6 +16,7 @@ const { getConnectionLabel, getLogger, extractErrorLogData } = require('dbgate-t const logger = getLogger('cloud'); const _ = require('lodash'); const fs = require('fs-extra'); +const { getAiGatewayServer } = require('../utility/authProxy'); module.exports = { publicFiles_meta: true, @@ -276,4 +277,17 @@ module.exports = { const resp = await callCloudApiPost(`content-folders/remove-user/${folid}`, { email }); return resp; }, + + getAiGateway_meta: true, + async getAiGateway() { + return getAiGatewayServer(); + }, + + // chatStream_meta: { + // raw: true, + // method: 'post', + // }, + // chatStream(req, res) { + // callChatStream(req.body, res); + // }, }; diff --git a/packages/web/package.json b/packages/web/package.json index 8874f20a8..b485383f3 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -69,6 +69,7 @@ "highlight.js": "^11.11.1", "interval-operations": "^1.0.7", "leaflet": "^1.8.0", + "openai": "^5.10.1", "wellknown": "^0.5.0", "xml-formatter": "^3.6.4" } diff --git a/packages/web/src/celldata/XmlCellView.svelte b/packages/web/src/celldata/XmlCellView.svelte index ca18a81dd..a95e9a1b1 100644 --- a/packages/web/src/celldata/XmlCellView.svelte +++ b/packages/web/src/celldata/XmlCellView.svelte @@ -1,5 +1,5 @@ diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index a1fc8f2c1..e37bd9b1a 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -714,6 +714,28 @@ if (isProApp()) { ); }, }); + + registerCommand({ + id: 'database.chat', + category: 'Database', + name: 'Database chat', + toolbar: true, + icon: 'icon ai', + testEnabled: () => + getCurrentDatabase() != null && + findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'), + onClick: () => { + openNewTab({ + title: 'Chat', + icon: 'img ai', + tabComponent: 'DatabaseChatTab', + props: { + conid: getCurrentDatabase()?.connection?._id, + database: getCurrentDatabase()?.name, + }, + }); + }, + }); } if (hasPermission('settings/change')) { diff --git a/packages/web/src/elements/SqlHighlighter.svelte b/packages/web/src/elements/SqlHighlighter.svelte new file mode 100644 index 000000000..41d3aa438 --- /dev/null +++ b/packages/web/src/elements/SqlHighlighter.svelte @@ -0,0 +1,41 @@ + + +{#key code} + +
{code}
+{/key} + + diff --git a/packages/web/src/celldata/XmlHighlighter.svelte b/packages/web/src/elements/XmlHighlighter.svelte similarity index 87% rename from packages/web/src/celldata/XmlHighlighter.svelte rename to packages/web/src/elements/XmlHighlighter.svelte index 2f5fe655c..794f9b13d 100644 --- a/packages/web/src/celldata/XmlHighlighter.svelte +++ b/packages/web/src/elements/XmlHighlighter.svelte @@ -6,7 +6,7 @@ export let code = ''; - $: formattedCode = xmlFormat(code, { indentation: ' ' }); + $: formattedCode = xmlFormat(code, { indentation: ' ', throwOnFailure: false }); onMount(() => { hljs.registerLanguage('xml', xmlGrammar); diff --git a/packages/web/src/elements/sqlGrammar.js b/packages/web/src/elements/sqlGrammar.js new file mode 100644 index 000000000..52d198b21 --- /dev/null +++ b/packages/web/src/elements/sqlGrammar.js @@ -0,0 +1,691 @@ +/* + Language: SQL + Website: https://en.wikipedia.org/wiki/SQL + Category: common, database + */ + +/* + +Goals: + +SQL is intended to highlight basic/common SQL keywords and expressions + +- If pretty much every single SQL server includes supports, then it's a canidate. +- It is NOT intended to include tons of vendor specific keywords (Oracle, MySQL, + PostgreSQL) although the list of data types is purposely a bit more expansive. +- For more specific SQL grammars please see: + - PostgreSQL and PL/pgSQL - core + - T-SQL - https://github.com/highlightjs/highlightjs-tsql + - sql_more (core) + + */ + +export default function(hljs) { + const regex = hljs.regex; + const COMMENT_MODE = hljs.COMMENT('--', '$'); + const STRING = { + scope: 'string', + variants: [ + { + begin: /'/, + end: /'/, + contains: [ { match: /''/ } ] + } + ] + }; + const QUOTED_IDENTIFIER = { + begin: /"/, + end: /"/, + contains: [ { match: /""/ } ] + }; + + const LITERALS = [ + "true", + "false", + // Not sure it's correct to call NULL literal, and clauses like IS [NOT] NULL look strange that way. + // "null", + "unknown" + ]; + + const MULTI_WORD_TYPES = [ + "double precision", + "large object", + "with timezone", + "without timezone" + ]; + + const TYPES = [ + 'bigint', + 'binary', + 'blob', + 'boolean', + 'char', + 'character', + 'clob', + 'date', + 'dec', + 'decfloat', + 'decimal', + 'float', + 'int', + 'integer', + 'interval', + 'nchar', + 'nclob', + 'national', + 'numeric', + 'real', + 'row', + 'smallint', + 'time', + 'timestamp', + 'varchar', + 'varying', // modifier (character varying) + 'varbinary' + ]; + + const NON_RESERVED_WORDS = [ + "add", + "asc", + "collation", + "desc", + "final", + "first", + "last", + "view" + ]; + + // https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#reserved-word + const RESERVED_WORDS = [ + "abs", + "acos", + "all", + "allocate", + "alter", + "and", + "any", + "are", + "array", + "array_agg", + "array_max_cardinality", + "as", + "asensitive", + "asin", + "asymmetric", + "at", + "atan", + "atomic", + "authorization", + "avg", + "begin", + "begin_frame", + "begin_partition", + "between", + "bigint", + "binary", + "blob", + "boolean", + "both", + "by", + "call", + "called", + "cardinality", + "cascaded", + "case", + "cast", + "ceil", + "ceiling", + "char", + "char_length", + "character", + "character_length", + "check", + "classifier", + "clob", + "close", + "coalesce", + "collate", + "collect", + "column", + "commit", + "condition", + "connect", + "constraint", + "contains", + "convert", + "copy", + "corr", + "corresponding", + "cos", + "cosh", + "count", + "covar_pop", + "covar_samp", + "create", + "cross", + "cube", + "cume_dist", + "current", + "current_catalog", + "current_date", + "current_default_transform_group", + "current_path", + "current_role", + "current_row", + "current_schema", + "current_time", + "current_timestamp", + "current_path", + "current_role", + "current_transform_group_for_type", + "current_user", + "cursor", + "cycle", + "date", + "day", + "deallocate", + "dec", + "decimal", + "decfloat", + "declare", + "default", + "define", + "delete", + "dense_rank", + "deref", + "describe", + "deterministic", + "disconnect", + "distinct", + "double", + "drop", + "dynamic", + "each", + "element", + "else", + "empty", + "end", + "end_frame", + "end_partition", + "end-exec", + "equals", + "escape", + "every", + "except", + "exec", + "execute", + "exists", + "exp", + "external", + "extract", + "false", + "fetch", + "filter", + "first_value", + "float", + "floor", + "for", + "foreign", + "frame_row", + "free", + "from", + "full", + "function", + "fusion", + "get", + "global", + "grant", + "group", + "grouping", + "groups", + "having", + "hold", + "hour", + "identity", + "in", + "indicator", + "initial", + "inner", + "inout", + "insensitive", + "insert", + "int", + "integer", + "intersect", + "intersection", + "interval", + "into", + "is", + "join", + "json_array", + "json_arrayagg", + "json_exists", + "json_object", + "json_objectagg", + "json_query", + "json_table", + "json_table_primitive", + "json_value", + "lag", + "language", + "large", + "last_value", + "lateral", + "lead", + "leading", + "left", + "like", + "like_regex", + "listagg", + "ln", + "local", + "localtime", + "localtimestamp", + "log", + "log10", + "lower", + "match", + "match_number", + "match_recognize", + "matches", + "max", + "member", + "merge", + "method", + "min", + "minute", + "mod", + "modifies", + "module", + "month", + "multiset", + "national", + "natural", + "nchar", + "nclob", + "new", + "no", + "none", + "normalize", + "not", + "nth_value", + "ntile", + "null", + "nullif", + "numeric", + "octet_length", + "occurrences_regex", + "of", + "offset", + "old", + "omit", + "on", + "one", + "only", + "open", + "or", + "order", + "out", + "outer", + "over", + "overlaps", + "overlay", + "parameter", + "partition", + "pattern", + "per", + "percent", + "percent_rank", + "percentile_cont", + "percentile_disc", + "period", + "portion", + "position", + "position_regex", + "power", + "precedes", + "precision", + "prepare", + "primary", + "procedure", + "ptf", + "range", + "rank", + "reads", + "real", + "recursive", + "ref", + "references", + "referencing", + "regr_avgx", + "regr_avgy", + "regr_count", + "regr_intercept", + "regr_r2", + "regr_slope", + "regr_sxx", + "regr_sxy", + "regr_syy", + "release", + "result", + "return", + "returns", + "revoke", + "right", + "rollback", + "rollup", + "row", + "row_number", + "rows", + "running", + "savepoint", + "scope", + "scroll", + "search", + "second", + "seek", + "select", + "sensitive", + "session_user", + "set", + "show", + "similar", + "sin", + "sinh", + "skip", + "smallint", + "some", + "specific", + "specifictype", + "sql", + "sqlexception", + "sqlstate", + "sqlwarning", + "sqrt", + "start", + "static", + "stddev_pop", + "stddev_samp", + "submultiset", + "subset", + "substring", + "substring_regex", + "succeeds", + "sum", + "symmetric", + "system", + "system_time", + "system_user", + "table", + "tablesample", + "tan", + "tanh", + "then", + "time", + "timestamp", + "timezone_hour", + "timezone_minute", + "to", + "trailing", + "translate", + "translate_regex", + "translation", + "treat", + "trigger", + "trim", + "trim_array", + "true", + "truncate", + "uescape", + "union", + "unique", + "unknown", + "unnest", + "update", + "upper", + "user", + "using", + "value", + "values", + "value_of", + "var_pop", + "var_samp", + "varbinary", + "varchar", + "varying", + "versioning", + "when", + "whenever", + "where", + "width_bucket", + "window", + "with", + "within", + "without", + "year", + ]; + + // these are reserved words we have identified to be functions + // and should only be highlighted in a dispatch-like context + // ie, array_agg(...), etc. + const RESERVED_FUNCTIONS = [ + "abs", + "acos", + "array_agg", + "asin", + "atan", + "avg", + "cast", + "ceil", + "ceiling", + "coalesce", + "corr", + "cos", + "cosh", + "count", + "covar_pop", + "covar_samp", + "cume_dist", + "dense_rank", + "deref", + "element", + "exp", + "extract", + "first_value", + "floor", + "json_array", + "json_arrayagg", + "json_exists", + "json_object", + "json_objectagg", + "json_query", + "json_table", + "json_table_primitive", + "json_value", + "lag", + "last_value", + "lead", + "listagg", + "ln", + "log", + "log10", + "lower", + "max", + "min", + "mod", + "nth_value", + "ntile", + "nullif", + "percent_rank", + "percentile_cont", + "percentile_disc", + "position", + "position_regex", + "power", + "rank", + "regr_avgx", + "regr_avgy", + "regr_count", + "regr_intercept", + "regr_r2", + "regr_slope", + "regr_sxx", + "regr_sxy", + "regr_syy", + "row_number", + "sin", + "sinh", + "sqrt", + "stddev_pop", + "stddev_samp", + "substring", + "substring_regex", + "sum", + "tan", + "tanh", + "translate", + "translate_regex", + "treat", + "trim", + "trim_array", + "unnest", + "upper", + "value_of", + "var_pop", + "var_samp", + "width_bucket", + ]; + + // these functions can + const POSSIBLE_WITHOUT_PARENS = [ + "current_catalog", + "current_date", + "current_default_transform_group", + "current_path", + "current_role", + "current_schema", + "current_transform_group_for_type", + "current_user", + "session_user", + "system_time", + "system_user", + "current_time", + "localtime", + "current_timestamp", + "localtimestamp" + ]; + + // those exist to boost relevance making these very + // "SQL like" keyword combos worth +1 extra relevance + const COMBOS = [ + "create table", + "insert into", + "primary key", + "foreign key", + "not null", + "alter table", + "add constraint", + "grouping sets", + "on overflow", + "character set", + "respect nulls", + "ignore nulls", + "nulls first", + "nulls last", + "depth first", + "breadth first" + ]; + + const FUNCTIONS = RESERVED_FUNCTIONS; + + const KEYWORDS = [ + ...RESERVED_WORDS, + ...NON_RESERVED_WORDS + ].filter((keyword) => { + return !RESERVED_FUNCTIONS.includes(keyword); + }); + + const VARIABLE = { + scope: "variable", + match: /@[a-z0-9][a-z0-9_]*/, + }; + + const OPERATOR = { + scope: "operator", + match: /[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, + relevance: 0, + }; + + const FUNCTION_CALL = { + match: regex.concat(/\b/, regex.either(...FUNCTIONS), /\s*\(/), + relevance: 0, + keywords: { built_in: FUNCTIONS } + }; + + // turns a multi-word keyword combo into a regex that doesn't + // care about extra whitespace etc. + // input: "START QUERY" + // output: /\bSTART\s+QUERY\b/ + function kws_to_regex(list) { + return regex.concat( + /\b/, + regex.either(...list.map((kw) => { + return kw.replace(/\s+/, "\\s+") + })), + /\b/ + ) + } + + const MULTI_WORD_KEYWORDS = { + scope: "keyword", + match: kws_to_regex(COMBOS), + relevance: 0, + }; + + // keywords with less than 3 letters are reduced in relevancy + function reduceRelevancy(list, { + exceptions, when + } = {}) { + const qualifyFn = when; + exceptions = exceptions || []; + return list.map((item) => { + if (item.match(/\|\d+$/) || exceptions.includes(item)) { + return item; + } else if (qualifyFn(item)) { + return `${item}|0`; + } else { + return item; + } + }); + } + + return { + name: 'SQL', + case_insensitive: true, + // does not include {} or HTML tags ` x.length < 3 }), + literal: LITERALS, + type: TYPES, + built_in: POSSIBLE_WITHOUT_PARENS + }, + contains: [ + { + scope: "type", + match: kws_to_regex(MULTI_WORD_TYPES) + }, + MULTI_WORD_KEYWORDS, + FUNCTION_CALL, + VARIABLE, + STRING, + QUOTED_IDENTIFIER, + hljs.C_NUMBER_MODE, + hljs.C_BLOCK_COMMENT_MODE, + COMMENT_MODE, + OPERATOR + ] + }; +} \ No newline at end of file diff --git a/packages/web/src/celldata/xmlGrammar.js b/packages/web/src/elements/xmlGrammar.js similarity index 100% rename from packages/web/src/celldata/xmlGrammar.js rename to packages/web/src/elements/xmlGrammar.js diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte index d2c5ef036..e293e3acf 100644 --- a/packages/web/src/icons/FontIcon.svelte +++ b/packages/web/src/icons/FontIcon.svelte @@ -73,6 +73,7 @@ 'icon scheduler-event': 'mdi mdi-calendar-blank', 'icon arrow-link': 'mdi mdi-arrow-top-right-thick', 'icon reset': 'mdi mdi-cancel', + 'icon send': 'mdi mdi-send', 'icon window-restore': 'mdi mdi-window-restore', 'icon window-maximize': 'mdi mdi-window-maximize', @@ -163,8 +164,10 @@ 'icon wait': 'mdi mdi-timer-sand', 'icon more': 'mdi mdi-more', 'icon copy': 'mdi mdi-content-copy', + 'icon arrow-start-here': 'mdi mdi-arrow-down-bold-circle', 'icon run': 'mdi mdi-play', + 'icon run-settings': 'mdi mdi-cog-play', 'icon chevron-down': 'mdi mdi-chevron-down', 'icon chevron-left': 'mdi mdi-chevron-left', 'icon chevron-right': 'mdi mdi-chevron-right', @@ -280,6 +283,8 @@ 'img admin': 'mdi mdi-security color-icon-blue', 'img auth': 'mdi mdi-account-key color-icon-blue', 'img cloud-connection': 'mdi mdi-cloud-lock color-icon-blue', + 'img ai': 'mdi mdi-head-lightbulb color-icon-yellow', + 'img run': 'mdi mdi-play color-icon-blue', 'img add': 'mdi mdi-plus-circle color-icon-green', 'img minus': 'mdi mdi-minus-circle color-icon-red', @@ -338,6 +343,7 @@ 'img db-restore': 'mdi mdi-database-import color-icon-red', 'img settings': 'mdi mdi-cog color-icon-blue', 'img data-deploy': 'mdi mdi-database-settings color-icon-green', + 'img arrow-start-here': 'mdi mdi-arrow-down-bold-circle color-icon-green', }; diff --git a/packages/web/src/modals/NewObjectModal.svelte b/packages/web/src/modals/NewObjectModal.svelte index 462a3820f..83a9691d1 100644 --- a/packages/web/src/modals/NewObjectModal.svelte +++ b/packages/web/src/modals/NewObjectModal.svelte @@ -105,6 +105,15 @@ disabledMessage: 'Database comparison is not available for current database', isProFeature: true, }, + { + icon: 'icon ai', + colorClass: 'color-icon-blue', + title: 'Database Chat', + description: 'Chat with your database using AI', + command: 'database.chat', + isProFeature: true, + disabledMessage: 'Database chat is not available for current database', + } ]; diff --git a/packages/web/src/query/QueryAiAssistant.svelte b/packages/web/src/query/QueryAiAssistant.svelte deleted file mode 100644 index b44912f77..000000000 --- a/packages/web/src/query/QueryAiAssistant.svelte +++ /dev/null @@ -1 +0,0 @@ -AI Assistant \ No newline at end of file diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index 4746dcff3..a2102fa72 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -13,15 +13,6 @@ testEnabled: () => getCurrentEditor()?.isSqlEditor(), onClick: () => getCurrentEditor().formatCode(), }); - registerCommand({ - id: 'query.switchAiAssistant', - category: 'Query', - name: 'AI Assistant', - keyText: 'Shift+Alt+A', - icon: 'icon ai', - testEnabled: () => isProApp(), - onClick: () => getCurrentEditor().toggleAiAssistant(), - }); registerCommand({ id: 'query.insertSqlJoin', category: 'Query', @@ -157,7 +148,6 @@ import QueryParametersModal from '../modals/QueryParametersModal.svelte'; import { isProApp } from '../utility/proTools'; import HorizontalSplitter from '../elements/HorizontalSplitter.svelte'; - import QueryAiAssistant from '../query/QueryAiAssistant.svelte'; import uuidv1 from 'uuid/v1'; import ToolStripButton from '../buttons/ToolStripButton.svelte'; import { getIntSettingsValue } from '../settings/settingsTools'; @@ -212,8 +202,6 @@ let domEditor; let domToolStrip; let intervalId; - let isAiAssistantVisible = isProApp() && localStorage.getItem(`tabdata_isAiAssistantVisible_${tabid}`) == 'true'; - let domAiAssistant; let isInTransaction = false; let isAutocommit = false; let splitterInitialValue = undefined; @@ -287,12 +275,6 @@ domEditor?.getEditor()?.focus(); } - $: { - if (!isAiAssistantVisible && domEditor) { - domEditor?.getEditor()?.focus(); - } - } - export function isSqlEditor() { return driver?.databaseEngineTypes?.includes('sql'); } @@ -317,10 +299,6 @@ visibleResultTabs = !visibleResultTabs; } - export function toggleAiAssistant() { - isAiAssistantVisible = !isAiAssistantVisible; - } - function getParameterSplitterOptions() { if (!queryParameterStyle) { return null; @@ -631,29 +609,6 @@ ); } - async function handleKeyDown(event) { - if (isProApp()) { - if (event.code == 'Space' && event.shiftKey && event.ctrlKey && !isAiAssistantVisible) { - event.preventDefault(); - event.stopPropagation(); - toggleAiAssistant(); - await sleep(100); - if (domAiAssistant) { - domAiAssistant.handleCompleteOnCursor(); - domEditor?.getEditor()?.focus(); - } - } else if (event.code == 'Space' && event.shiftKey && event.ctrlKey && isAiAssistantVisible && domAiAssistant) { - event.preventDefault(); - event.stopPropagation(); - domAiAssistant.handleCompleteOnCursor(); - } else if (event.code?.startsWith('Digit') && event.altKey && isAiAssistantVisible && domAiAssistant) { - event.preventDefault(); - event.stopPropagation(); - domAiAssistant.insertCompletion(parseInt(event.code.substring(5)) - 1); - } - } - } - function createMenu() { return [ { command: 'query.execute' }, @@ -675,7 +630,6 @@ { command: 'query.replace' }, { divider: true }, { command: 'query.toggleVisibleResultTabs' }, - { command: 'query.switchAiAssistant', hideDisabled: true }, ]; } @@ -695,127 +649,91 @@ localStorage.getItem(`tabdata_queryParamStyle_${tabid}`) ?? initialArgs?.queryParameterStyle ?? (initialArgs?.scriptTemplate == 'CALL OBJECT' ? ':' : ''); - - $: localStorage.setItem(`tabdata_isAiAssistantVisible_${tabid}`, isAiAssistantVisible ? 'true' : 'false'); - + - - - {#if driver?.databaseEngineTypes?.includes('sql')} - { - setEditorData(e.detail); - if (isInitialized) { - markTabUnsaved(tabid); - } - errorMessages = []; - }} - on:focus={() => { - activator.activate(); - domToolStrip?.activate(); - invalidateCommands(); - setTimeout(() => { - isInitialized = true; - }, 100); - }} - bind:this={domEditor} - onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)} - {errorMessages} - onKeyDown={handleKeyDown} - /> - {:else} - setEditorData(e.detail)} - on:focus={() => { - activator.activate(); - domToolStrip?.activate(); - invalidateCommands(); - }} - bind:this={domEditor} - /> - {/if} - - - getSqlFrontMatter($editorValue, yaml)} - > - - - - - - + {#if driver?.databaseEngineTypes?.includes('sql')} + { + setEditorData(e.detail); + if (isInitialized) { + markTabUnsaved(tabid); + } + errorMessages = []; + }} + on:focus={() => { + activator.activate(); + domToolStrip?.activate(); + invalidateCommands(); + setTimeout(() => { + isInitialized = true; + }, 100); + }} + bind:this={domEditor} + onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)} + {errorMessages} + /> + {:else} + setEditorData(e.detail)} + on:focus={() => { + activator.activate(); + domToolStrip?.activate(); + invalidateCommands(); + }} + bind:this={domEditor} + /> + {/if} - { - isAiAssistantVisible = false; - }} - text={$editorValue} - getLine={() => domEditor.getEditor().getSelectionRange().start.row} - onInsertAtCursor={text => { - const editor = domEditor.getEditor(); - editor.session.insert(editor.getCursorPosition(), text); - domEditor?.getEditor()?.focus(); - }} - getTextOrSelectedText={() => domEditor.getEditor().getSelectedText() || $editorValue} - onSetSelectedText={text => { - const editor = domEditor.getEditor(); - if (editor.getSelectedText()) { - const range = editor.selection.getRange(); - editor.session.replace(range, text); - } else { - editor.setValue(text); - } - }} - {tabid} - /> + onSetFrontMatterField={handleSetFrontMatterField} + onGetFrontMatter={() => getSqlFrontMatter($editorValue, yaml)} + > + + + + - + - - AI Assistant - { + $selectedWidget = 'plugins'; + $visibleWidgetSideBar = true; + }, + }, ]; currentDropDownMenu.set({ left, top, items }); } @@ -159,6 +166,7 @@ {#each widgets .filter(x => x && hasPermission(`widgets/${x.name}`)) .filter(x => !x.isPremiumPromo || !isProApp()) + // .filter(x => !x.isPremiumOnly || isProApp()) .filter(x => x.name != 'cloud-private' || $cloudSigninTokenHolder) as item}