{"export":{"version":"v1","entries":{"widget":{"1":{"widget":{"data":{"shared":{"sort":[],"type":"datalens","links":[],"colors":[],"labels":[],"shapes":[],"convert":false,"filters":[{"guid":"creation_dt_4enj","type":"DIMENSION","title":"creation_dt","filter":{"value":["__interval_2024-08-04T00:00:00.000Z_2024-11-23T00:00:00.000Z"],"operation":{"code":"BETWEEN"}},"calc_mode":"direct","datasetId":"4"}],"updates":[],"version":"14","segments":[],"tooltips":[],"datasetsIds":["4"],"hierarchies":[],"colorsConfig":{},"shapesConfig":{},"extraSettings":{},"visualization":{"id":"line","name":"label_visualization-line","type":"line","allowSort":true,"iconProps":{"id":"visLines","width":"24"},"allowColors":true,"allowLabels":true,"allowShapes":true,"allowFilters":true,"placeholders":[{"id":"x","type":"x","items":[{"id":"inserted-1757429627587","cast":"genericdatetime","guid":"a939feb0-8ca8-11f0-a219-ffe370dfee11","type":"DIMENSION","title":"Date scaled","valid":true,"hidden":false,"source":"","formula":"DATETRUNC([delivery_dt],[date_scale])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"genericdatetime","datasetId":"4","managed_by":"user","aggregation":"none","datasetName":"MarketPlace AI Demo","description":"","ui_settings":"","guid_formula":"DATETRUNC([delivery_dt_y2sz],[date_scale])","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"genericdatetime","aggregation_locked":true,"has_auto_aggregation":false}],"title":"section_x","capacity":1,"required":true,"settings":{"grid":"on","type":"linear","title":"off","gridStep":"auto","holidays":"off","hideLabels":"no","labelsView":"auto","titleValue":"","axisModeMap":{"a939feb0-8ca8-11f0-a219-ffe370dfee11":"continuous"},"gridStepValue":50,"axisFormatMode":"auto","axisVisibility":"show","axisLabelFormating":{},"axisLabelDateFormat":"DD.MM.YYYY"},"iconProps":{},"allowedTypes":{},"allowedDataTypes":{}},{"id":"y","type":"y","items":[{"id":"inserted-1757429619781","cast":"float","guid":"de256650-710a-11f0-a040-7f2cfa045483","type":"MEASURE","title":"GMV","valid":true,"hidden":false,"source":"","formula":"sum([amount])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"float","datasetId":"4","managed_by":"user","aggregation":"none","datasetName":"MarketPlace AI Demo","description":"","ui_settings":"","guid_formula":"sum([amount_52rb])","default_value":null,"autoaggregated":true,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"float","aggregation_locked":true,"has_auto_aggregation":true}],"title":"section_y","settings":{"grid":"on","type":"linear","nulls":"connect","scale":"auto","title":"off","gridStep":"auto","hideLabels":"no","labelsView":"auto","scaleValue":"min-max","titleValue":"","gridStepValue":50,"axisFormatMode":"auto","axisVisibility":"show","axisLabelFormating":{},"axisLabelDateFormat":"DD.MM.YYYY"},"iconProps":{},"allowedTypes":{},"allowedDataTypes":{},"allowedFinalTypes":{}},{"id":"y2","type":"y2","items":[],"title":"section_y2","settings":{"grid":"on","type":"linear","nulls":"connect","scale":"auto","title":"off","gridStep":"auto","hideLabels":"no","labelsView":"auto","scaleValue":"min-max","titleValue":"","gridStepValue":50,"axisFormatMode":"auto","axisVisibility":"show","axisLabelFormating":{},"axisLabelDateFormat":"DD.MM.YYYY"},"iconProps":{},"allowedTypes":{},"allowedDataTypes":{},"allowedFinalTypes":{}}],"allowSegments":true,"colorsCapacity":1,"shapesCapacity":1,"allowLayerFilters":false,"availableLabelModes":["absolute"]},"geopointsConfig":{},"datasetsPartialFields":[[{"guid":"78cf2b50-8ca9-11f0-a219-ffe370dfee11","title":"Orders","calc_mode":"formula"},{"guid":"374b78a0-8ca9-11f0-a219-ffe370dfee11","title":"AOV","calc_mode":"formula"},{"guid":"a939feb0-8ca8-11f0-a219-ffe370dfee11","title":"Date scaled","calc_mode":"formula"},{"guid":"date_scale","title":"date_scale","calc_mode":"parameter"},{"guid":"de256650-710a-11f0-a040-7f2cfa045483","title":"GMV","calc_mode":"formula"},{"guid":"category_level_1_n71b","title":"category_level_1","calc_mode":"direct"},{"guid":"category_level_2_exd4","title":"category_level_2","calc_mode":"direct"},{"guid":"category_level_3_50lm","title":"category_level_3","calc_mode":"direct"},{"guid":"region_delivery_efn9","title":"region_delivery","calc_mode":"direct"},{"guid":"city_delivery_ho3c","title":"city_delivery","calc_mode":"direct"},{"guid":"delivery_type_juix","title":"delivery_type","calc_mode":"direct"},{"guid":"delivery_service_blbn","title":"delivery_service","calc_mode":"direct"},{"guid":"sku_color_xokm","title":"sku_color","calc_mode":"direct"},{"guid":"user_gender_fqvv","title":"user_gender","calc_mode":"direct"},{"guid":"user_platform_rhsy","title":"user_platform","calc_mode":"direct"},{"guid":"user_id_9k0n","title":"user_id","calc_mode":"direct"},{"guid":"order_id_iejj","title":"order_id","calc_mode":"direct"},{"guid":"creation_dt_4enj","title":"creation_dt","calc_mode":"direct"},{"guid":"delivery_dt_y2sz","title":"delivery_dt","calc_mode":"direct"},{"guid":"amount_52rb","title":"amount","calc_mode":"direct"}]]}},"name":"Dynamic_line","type":"graph_wizard_node","annotation":null}},"2":{"widget":{"data":{"meta":"{\n    \"links\": {}\n}","params":"module.exports = {\n    backgroundColor: 'var(--g-color-base-info-light)',\n    //https://storage.yandexcloud.net/skaradubpics/bi_battle_logo.svg\n    companyLogo: '',\n    companyLogoLink: 'https://datalens.yandex.cloud/',\n    titleSize: '20',\n    title: 'Поиск аналитики',\n    subtitle: 'Тернистый путь к данным',\n    dashOwner: 'Юра',\n    dashOwnerLink: 'https://yandex.cloud/ru/docs/datalens/',\n    buttonTgLink: 'https://t.me/data2viz',\n};\n","prepare":"const params = Editor.getParams();\n\nconst tgImgSrc = 'https://storage.yandexcloud.net/datalens-public-demo-assets/telegram_blue.svg';\nconst logoSrc = 'https://storage.yandexcloud.net/skaradubpics/logo.png';\nconst docsImgSrc = 'https://storage.yandexcloud.net/datalens-public-demo-assets/documentation_icon.svg';\n\nconst titleSize = params.titleSize?.[0] || '19';\n\nconst config = {\n    backgroundColor: params.backgroundColor?.[0] ?? '',\n    logo: params.companyLogo?.[0] || logoSrc,\n    logoLink: params.companyLogoLink?.[0] || '',\n    title: params.title?.[0] || '',\n    titleSize: `${titleSize}px`,\n    subtitle: params.subtitle?.[0] || '',\n    dashOwner: params.dashOwner?.[0] || '',\n    dashOwnerLink: params.dashOwnerLink?.[0] || '',\n    tgImgSrc,\n    docsImgSrc,\n    updatedDate: '17.04',\n    updatedTime: '4 hours ago',\n    buttonTgLink: params.buttonTgLink?.[0] || '',\n    buttonDocLink: params.buttonDocLink?.[0] || '',\n};\n\nmodule.exports = {\n    render: Editor.wrapFn({\n        fn: function(_dimensions, config) {\n            function getIconWithLinkItem(img, link) {\n                if (!img || !link) {\n                    return '';\n                }\n                return `\n                    <div style=\"display: flex; flex-direction: column; justify-content: center; padding: 0px 0px 0px 10px;\">\n                        <a href=\"${link}\"><img src=\"${img}\" style=\"width: 20px;\" /></a>\n                    </div>\n                `;\n            }\n            function getControls(controls) {\n                let res = '';\n                controls.forEach(item => {\n                    if (item.link && item.img) {\n                        res += getIconWithLinkItem(item.img, item.link);\n                    }\n                });\n                return res;\n            }\n\n            const logoBlock = `\n                <div style=\"display: flex; flex-direction: row; align-items: center; padding: 0px 5px; justify-content: center;\">\n                    <img src=\"${config.logo}\" style=\"max-width:50px;display: block;\" />\n                </div>\n            `;\n\n            const logo = config.logoLink ? `<a href=\"${config.logoLink}\" target=\"_blank\">${logoBlock}</a>` : `<span>${logoBlock}</span>`;\n            const dashOwner = config.dashOwnerLink ? `<a href=\"${config.dashOwnerLink}\" target=\"_blank\" style=\"color: var(--g-color-text-link); text-decoration: none;\">${config.dashOwner}</a>` : `<span>${config.dashOwner}</span>`\n            const subtitle = config.subtitle ? `<i>${config.subtitle}</i>` : '';\n\n            const dashOwnerBlock = config.dashOwner ? `\n                <div>\n                    <span>Админ дашборда:&nbsp;</span>\n                    ${dashOwner}\n                </div>\n            ` : '';\n\n            const description = `\n                <div style=\"display: flex; flex-direction: column; padding: 0px 0px 0px 5px; justify-content: center;\">\n                    <span style=\"font-size: 19px; line-height: 1.3em; font-weight: bold;\">${config.title}</span>\n                    <span style=\"color: var(--g-color-text-secondary); font-size: 11px; line-height: 1.1em; font-weight: normal;\">\n                        ${subtitle}\n                        ${dashOwnerBlock}\n                    </span>\n                </div>\n            `;\n\n            const controls = [];\n            if (config.buttonTgLink) {\n                controls.push({img: config.tgImgSrc, link: config.buttonTgLink});\n            }\n            if (config.buttonDocLink) {\n                controls.push({img: config.docsImgSrc, link: config.buttonDocLink});\n            }\n            const iconsBlock = getControls(controls);\n\n            const dateUpdate = `\n                <div style=\"\n                        min-height: 36px;\n                        background-color: var(--g-color-base-neutral-light-hover);\n                        border-radius: 5px;\n                        display: flex;\n                        align-items: center;\n                        justify-content: space-between;\n                        flex-direction: row;\n                        width: fit-content;\n                        padding: 1px 0px;\n                        margin-left: 20px;\n                \">\n                    <div style=\"width: 16px; transform: rotate(-90deg); display: flex; justify-content: center;\">\n                        <span style=\"font-size: 9px; color: var(--g-color-text-complementary);\">DATA</span>\n                    </div>\n                    <div style=\"display: flex; align-items: center; justify-content: space-between; gap: 5px; margin-right: 5px;\">\n                        <div style=\"padding: 1px 5px;\n                            width: fit-content;\n                            border-radius: 4px;\n                            display: flex;\n                            flex-direction: row;\n                            align-items: center;\n                            justify-content: space-between;\n                            gap: 3px;\n                            height: 26px;\n                            background-color: var(--g-color-base-float);\"\n                        >\n                            <div style=\"\n                                display: flex;\n                                flex-direction: column;\n                                line-height: 0;\n                                align-items: flex-start;\n                                justify-content: space-around;\n                                padding: 1px 0px;\n                                white-space: nowrap;\n                                margin: 0px;\n                            \">\n                                <span style=\"font-size: 11px; line-height: 1.2; font-weight: bold; color: var(--g-color-text-complementary);\">${config.updatedDate}</span>\n                                <span style=\"font-size: 9px; line-height: 1.2; color: var(--g-color-text-secondary);\">Upd: ${config.updatedTime}</span>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            `;\n\n            const cellItemStyles = `\n                display: flex;\n                flex-direction: row;\n                align-items: center;\n            `;\n            const content = `\n                <div style=\"\n                    display: flex;\n                    flex-direction: row;\n                    align-items: center;\n                    width: 100%;\n                    justify-content: space-between;\n                    gap: 20px;\n                    padding: 8px 24px;\n                \">\n                    <div style=\"${cellItemStyles}\">\n                        ${logo}\n                        ${description}\n                    </div>\n                    <div style=\"${cellItemStyles}\">\n                        <div style=\"display: flex; flex-direction: row; align-items: center; margin-right:20px;\">\n                            ${iconsBlock}\n                        </div>\n                    </div>\n                </div>\n            `;\n\n            return Editor.generateHtml(content);\n        },\n        args: [config],\n        libs: ['d3'],\n    }),\n};\n","sources":"module.exports = {};\n","controls":"module.exports = {};\n"},"name":"finance_header","type":"advanced-chart_node","annotation":{"description":""}}},"3":{"widget":{"data":{"shared":{"sort":[],"type":"datalens","links":[],"colors":[],"labels":[],"shapes":[],"convert":false,"filters":[{"guid":"creation_dt_4enj","type":"DIMENSION","title":"creation_dt","filter":{"value":["__interval_2024-08-04T00:00:00.000Z_2024-11-23T00:00:00.000Z"],"operation":{"code":"BETWEEN"}},"calc_mode":"direct","datasetId":"4"}],"updates":[],"version":"14","segments":[],"tooltips":[],"datasetsIds":["4"],"hierarchies":[],"colorsConfig":{},"shapesConfig":{},"extraSettings":{},"visualization":{"id":"metric","name":"label_visualization-metric","type":"metric","allowSort":false,"iconProps":{"id":"visMetric","width":"24"},"allowLabels":false,"allowFilters":true,"placeholders":[{"id":"measures","type":"measures","items":[{"id":"inserted-1757429890906","cast":"float","guid":"de256650-710a-11f0-a040-7f2cfa045483","type":"MEASURE","title":"GMV","valid":true,"hidden":false,"source":"","formula":"sum([amount])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"float","datasetId":"4","formatting":{"unit":"auto","format":"number","prefix":"","postfix":"","labelMode":"absolute","precision":1,"showRankDelimiter":true},"managed_by":"user","aggregation":"none","datasetName":"MarketPlace AI Demo","description":"","ui_settings":"","guid_formula":"sum([amount_52rb])","default_value":null,"hideLabelMode":"show","autoaggregated":true,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"float","aggregation_locked":true,"has_auto_aggregation":true}],"title":"section_measure","capacity":1,"required":true,"settings":{"axisModeMap":{"de256650-710a-11f0-a040-7f2cfa045483":"discrete"}},"iconProps":{},"allowedTypes":{},"allowedDataTypes":{},"allowedFinalTypes":{}}],"allowLayerFilters":false},"geopointsConfig":{},"datasetsPartialFields":[[{"guid":"78cf2b50-8ca9-11f0-a219-ffe370dfee11","title":"Orders","calc_mode":"formula"},{"guid":"374b78a0-8ca9-11f0-a219-ffe370dfee11","title":"AOV","calc_mode":"formula"},{"guid":"a939feb0-8ca8-11f0-a219-ffe370dfee11","title":"Date scaled","calc_mode":"formula"},{"guid":"date_scale","title":"date_scale","calc_mode":"parameter"},{"guid":"de256650-710a-11f0-a040-7f2cfa045483","title":"GMV","calc_mode":"formula"},{"guid":"category_level_1_n71b","title":"category_level_1","calc_mode":"direct"},{"guid":"category_level_2_exd4","title":"category_level_2","calc_mode":"direct"},{"guid":"category_level_3_50lm","title":"category_level_3","calc_mode":"direct"},{"guid":"region_delivery_efn9","title":"region_delivery","calc_mode":"direct"},{"guid":"city_delivery_ho3c","title":"city_delivery","calc_mode":"direct"},{"guid":"delivery_type_juix","title":"delivery_type","calc_mode":"direct"},{"guid":"delivery_service_blbn","title":"delivery_service","calc_mode":"direct"},{"guid":"sku_color_xokm","title":"sku_color","calc_mode":"direct"},{"guid":"user_gender_fqvv","title":"user_gender","calc_mode":"direct"},{"guid":"user_platform_rhsy","title":"user_platform","calc_mode":"direct"},{"guid":"user_id_9k0n","title":"user_id","calc_mode":"direct"},{"guid":"order_id_iejj","title":"order_id","calc_mode":"direct"},{"guid":"creation_dt_4enj","title":"creation_dt","calc_mode":"direct"},{"guid":"delivery_dt_y2sz","title":"delivery_dt","calc_mode":"direct"},{"guid":"amount_52rb","title":"amount","calc_mode":"direct"}]]}},"name":"Indicator","type":"metric_wizard_node","annotation":null}},"5":{"widget":{"data":{"meta":"{\n    \"links\": {\n        \"dataset\": \"4\"\n    }\n}","config":"\n\nmodule.exports = {\n    title: {\n        text: 'Детализация сводных данных',\n        style: {\n            'text-align': 'left',\n            'font-size': '16px',\n            'font-style': 'italic',\n            'color': 'var(--g-color-text-hint)',\n            'margin-bottom': '16px',\n        }\n    },\n    size: 'l',\n    sort: 'id-rand-int',\n    order: 'asc',\n};\n","params":"module.exports = {\n    // разрезы к визуализации по строкам\n    dimension_1:['region_delivery'],\n    dimension_2:[''],\n    dimension_3:[''],\n    dimension_4:[''],\n    dimension_5:[''],\n    // разрезы к визуализации по столбцам\n    dim_col1:['Date scaled'],\n    // тут надо перечислить поля, которые будут участвовать в фильтрации из датасета, для этого в датасете нажмите \"показать id\" и скопируйте сюда idшники\n    filter_fields_ids:['product_type_rrf6|store_name_rus_3aut|product_name_rjpb|gtin_icnr'],\n    // передача массового значения из эксель, например, и подстановка в IN оператор, влияет положительно на производительность\n    mass_filter_fields_ids:['gtin_icnr'],\n    // Список метрик к отрисовке, для self-service анализа заводите как параметр ручного ввода на дашборд\n    metrics_list:['GMV','Orders'],\n    // NEW ATTRIBUTE alias_en TO WORK WITH\n    metrics_defs:[`{\n        \"Orders\":{\"alias_en\":\"Orders, cnt\",\"alias\":\"Заказы\",\"type\":\"abs\"},\n        \"GMV\":{\"alias_en\":\"Sales, rub\",\"alias\":\"Продажи, руб\",\"type\":\"abs\",\"def\":\"Продано по централизованным ценам\"}\n        }`],\n    // параметр ручного ввода ввести на дашборде - он автоматически свяжется\n    date_interval:['__interval_2024-08-12T00:00:00.000Z_2024-08-18T00:00:00.000Z'],\n    // параметр ручного ввода ввести на дашборде - он автоматически свяжется\n    date_scale:['week'],\n    // поле, которое имеет формулу DATETRUNC([some_date],[date_scale]) для приведения к началу периода\n    date_dimension:['Date scaled'],\n    // Поле для фильтра данных в таблице, не равно полю с приведением к началу месяца, чтобы можно было оптимально выбирать данные\n    filter_date_dimension:['creation_dt'],\n    // сколько строк выбирать из источника LIMIT\n    row_limit:['1000'],\n    // какой вид таблички генерировать, в текущей версии только PoP\n    table_type:['pop'],\n    // список к передаче параметров в датасет\n    params_to_send:['date_scale|'],\n    // что показывать в отклонениях, лучше вывести как параметр на дашбдорд, значения abs, %, both\n\n        //FOR THE BEAUTY\n    date_format:['DD.MM'],\n    heatmap:['true'],\n    heatmap_color:['#BBFFAA'],\n    heatmap_percentile:['50'],\n    // NEW FEATURE TO WORK WITH\n    lang:['ru']\n};","prepare":"// Импорт необходимых библиотек и получение параметров\nconst {dateTimeParse} = require('@gravity-ui/date-utils'); // Библиотека для работы с датами\nconst Dataset = require('libs/dataset/v2'); // Библиотека для обработки данных\nconst params = Editor.getParams(); // Получение параметров из редактора\n\nfunction createPivotTable(preparedData, rows_dims, cols_dims, metrics, params) {\n    const head = []; // Массив для заголовков таблицы\n    const rows = []; // Массив для строк таблицы\n    \n    // Получаем параметры форматирования\n    const dateFormat = params.date_format && params.date_format[0] ? params.date_format[0] : \"YYYY-MM-DD\"; // Формат даты\n    const metrics_defs = JSON.parse(params.metrics_defs[0]); // Определения метрик\n    const useHeatmap = metrics.length === 1 && params.heatmap && params.heatmap[0] === 'true'; // Использовать тепловую карту?\n    const heatmapColor = params.heatmap_color && params.heatmap_color[0] ? params.heatmap_color[0] : '#ff0000'; // Цвет тепловой карты\n    const heatmapPercentile = params.heatmap_percentile && params.heatmap_percentile[0] ? \n                             parseInt(params.heatmap_percentile[0], 10) : 10; // Процентиль для тепловой карты\n\n\n    function isDateDimension(dimensionName) {\n        return dimensionName.toLowerCase().includes('дата') || \n               dimensionName.toLowerCase().includes('date');\n    }\n    \n\n    function formatDateTime(value, format) {\n        if (!value) return '';\n        \n        try {\n            const date = new Date(value);\n            if (isNaN(date.getTime())) return value; // Если не удалось распарсить дату, возвращаем исходное значение\n            return dateTimeParse(value).format(format); // Форматируем дату\n        } catch (e) {\n            return value; // В случае ошибки возвращаем исходное значение\n        }\n    }\n\n\n    function compareDates(a, b) {\n        const dateA = new Date(a);\n        const dateB = new Date(b);\n        \n        // Если не удалось распарсить даты, сравниваем как строки\n        if (isNaN(dateA.getTime()) || isNaN(dateB.getTime())) {\n            return String(a).localeCompare(String(b));\n        }\n        \n        return dateA - dateB; // Разница между датами\n    }\n    \n\n    function getUniqueValues(data, dimension) {\n        const values = new Set(); // Используем Set для хранения уникальных значений\n        data.forEach(item => {\n            const value = item[dimension] !== undefined ? item[dimension] : \"Undefined\"; // Если значения нет, используем \"Undefined\"\n            values.add(value);\n        });\n        \n        const uniqueValues = Array.from(values); // Преобразуем Set в массив\n        \n        // Сортируем по-разному в зависимости от типа измерения\n        return isDateDimension(dimension) ? uniqueValues.sort(compareDates) : uniqueValues.sort();\n    }\n    \n\n    function aggregateData() {\n        const aggregated = {}; // Объект для хранения агрегированных данных\n        \n        preparedData.forEach(item => {\n            // Создаем ключи для строк и столбцов\n            const rowKey = rows_dims.map(dim => item[dim]).join('|');\n            const colKey = cols_dims.map(dim => item[dim]).join('|');\n            \n            // Инициализируем структуру для строки, если ее еще нет\n            if (!aggregated[rowKey]) {\n                aggregated[rowKey] = {\n                    row_values: rows_dims.map(dim => item[dim]), // Значения измерений для строки\n                    columns: {}\n                };\n            }\n            \n            // Инициализируем структуру для столбца, если его еще нет\n            if (!aggregated[rowKey].columns[colKey]) {\n                aggregated[rowKey].columns[colKey] = {\n                    col_values: cols_dims.map(dim => item[dim]), // Значения измерений для столбца\n                    metrics: {}\n                };\n            }\n            \n            // Суммируем метрики для каждой комбинации строки и столбца\n            metrics.forEach(metric => {\n                if (!aggregated[rowKey].columns[colKey].metrics[metric]) {\n                    aggregated[rowKey].columns[colKey].metrics[metric] = 0;\n                }\n                aggregated[rowKey].columns[colKey].metrics[metric] += Number(item[metric]) || 0;\n            });\n        });\n        \n        return aggregated;\n    }\n    \n    /**\n     * Генерирует заголовки таблицы\n     */\n    function generateHeaders() {\n        // Добавляем заголовки для измерений строк\n        rows_dims.forEach((dim, index) => {\n            head.push({\n                id: `dim_${index}`,\n                name: dim,\n                type: 'text',\n                css: { 'font-weight': 'bold' }, // Жирный шрифт для заголовков\n                group: false,\n                width: 150\n            });\n        });\n\n        // Если нет измерений для столбцов, добавляем метрики как обычные столбцы\n        if (cols_dims.length === 0) {\n            metrics.forEach(metric => {\n                head.push({\n                    id: `metric_${metric}`,\n                    name: metric,\n                    type: 'text',\n                    css: { 'font-weight': 'bold' },\n                    group: false,\n                    width: 120,\n                    hint: metrics_defs[metric] ? metrics_defs[metric].def : undefined // Добавляем подсказку, если есть\n                });\n            });\n            return;\n        }\n\n        function buildColumnHeaderHierarchy() {\n            const uniqueColValues = {}; // Уникальные значения для каждого измерения столбцов\n            cols_dims.forEach(dim => {\n                uniqueColValues[dim] = getUniqueValues(preparedData, dim);\n            });\n\n\n            function buildHeadersRecursive(level, path = [], headersByLevel = {}) {\n                if (level >= cols_dims.length) return headersByLevel;\n\n                const dim = cols_dims[level]; // Текущее измерение\n\n                uniqueColValues[dim].forEach(value => {\n                    const currentPath = [...path, value]; // Добавляем текущее значение к пути\n                    const pathKey = currentPath.join('|'); // Ключ для пути\n\n                    if (!headersByLevel[level]) headersByLevel[level] = []; // Инициализируем массив для уровня\n\n                    // Проверяем, есть ли уже такой заголовок\n                    const existingHeader = headersByLevel[level].find(h => h.path === pathKey);\n\n                    if (!existingHeader) {\n                        let headerValue = value;\n                        // Форматируем дату, если нужно\n                        if (isDateDimension(dim)) {\n                            headerValue = formatDateTime(value, dateFormat);\n                        }\n\n                        // Добавляем заголовок\n                        headersByLevel[level].push({\n                            value: headerValue,\n                            originalValue: value,\n                            path: pathKey,\n                            parent: path.join('|')\n                        });\n                    }\n\n                    // Рекурсивно обрабатываем следующий уровень\n                    buildHeadersRecursive(level + 1, currentPath, headersByLevel);\n                });\n\n                return headersByLevel;\n            }\n\n            return buildHeadersRecursive(0);\n        }\n\n        // Если есть измерения для столбцов, строим иерархию заголовков\n        if (cols_dims.length > 0) {\n            const headerHierarchy = buildColumnHeaderHierarchy();\n            const addedMetrics = new Set(); // Для отслеживания добавленных метрик\n            \n\n            function buildHeadersForMatrix(headerHierarchy) {\n                return headerHierarchy[0].map(header => {\n\n                    function createSubHeaders(header, level) {\n                        // Если достигли последнего уровня, добавляем метрики\n                        if (level >= cols_dims.length) {\n                            return metrics.map(metric => ({\n                                id: `${header.path}_${metric}`,\n                                name: metric,\n                                width: 150,\n                                type: 'text',\n                                css: { 'text-align': 'center' },\n                                hint: addedMetrics.has(metric) ? undefined : (metrics_defs[metric] ? metrics_defs[metric].def : undefined),\n                                addedMetrics: addedMetrics.add(metric) // Отмечаем метрику как добавленную\n                            }));\n                        }\n\n                        // Ищем подзаголовки для текущего заголовка\n                        const children = headerHierarchy[level].filter(h => h.parent === header.path);\n\n                        // Если нет подзаголовков, добавляем метрики\n                        if (children.length === 0) {\n                            const localAddedMetrics = new Set();\n                            return metrics.map(metric => ({\n                                id: `${header.path}_${metric}`,\n                                name: metric,\n                                width: 120,\n                                type: 'text',\n                                css: { 'text-align': 'center' },\n                                hint: localAddedMetrics.has(metric) ? undefined : (metrics_defs[metric] ? metrics_defs[metric].def : undefined),\n                                addedMetrics: localAddedMetrics.add(metric)\n                            }));\n                        }\n\n                        // Рекурсивно обрабатываем подзаголовки\n                        return children.map(child => ({\n                            name: child.value,\n                            type: 'text',\n                            css: { 'font-weight': 'bold', 'text-align': 'center' },\n                            sub: createSubHeaders(child, level + 1)\n                        }));\n                    }\n\n                    // Создаем заголовок верхнего уровня с подзаголовками\n                    return {\n                        name: header.value,\n                        type: 'text',\n                        css: { 'font-weight': 'bold', 'text-align': 'center' },\n                        sub: createSubHeaders(header, 1)\n                    };\n                });\n            }\n\n            // Добавляем заголовки для матрицы\n            head.push(...buildHeadersForMatrix(headerHierarchy));\n        }\n    }\n    \n\n    function organizeRowsHierarchically(aggregatedData) {\n        // Если нет измерений для строк, возвращаем пустую строку\n        if (rows_dims.length === 0) {\n            return [{ row_values: [], data: aggregatedData }];\n        }\n        \n        const rowHierarchy = {}; // Иерархия строк\n        \n        // Создаем иерархию строк\n        Object.values(aggregatedData).forEach(rowData => {\n            let current = rowHierarchy;\n            \n            for (let i = 0; i < rows_dims.length; i++) {\n                const value = rowData.row_values[i];\n                \n                if (i === rows_dims.length - 1) {\n                    // Последний уровень - добавляем данные\n                    if (!current[value]) {\n                        current[value] = { data: rowData };\n                    }\n                } else {\n                    // Промежуточный уровень - добавляем дочерние элементы\n                    if (!current[value]) {\n                        current[value] = { children: {} };\n                    }\n                    current = current[value].children;\n                }\n            }\n        });\n        \n        const flatRows = []; // Плоский список строк\n        \n        function flattenHierarchy(node, level = 0, ancestors = []) {\n            let keys = Object.keys(node).filter(k => k !== 'children' && k !== 'data');\n            \n            // Сортируем ключи\n            if (level < rows_dims.length && isDateDimension(rows_dims[level])) {\n                keys = keys.sort(compareDates); // Сортировка дат\n            } else {\n                keys = keys.sort(); // Обычная сортировка\n            }\n            \n            keys.forEach(value => {\n                const row = node[value];\n                const currentValues = [...ancestors];\n                \n                currentValues[level] = value; // Добавляем текущее значение\n                \n                if (row.data) {\n                    // Добавляем строку с данными\n                    flatRows.push({\n                        row_values: currentValues,\n                        data: row.data\n                    });\n                }\n                \n                if (row.children) {\n                    // Рекурсивно обрабатываем дочерние элементы\n                    flattenHierarchy(row.children, level + 1, currentValues);\n                }\n            });\n        }\n        \n        flattenHierarchy(rowHierarchy, 0, new Array(rows_dims.length).fill(null));\n        return flatRows;\n    }\n    \n    function fillRows() {\n        const aggregatedData = aggregateData(); // Агрегированные данные\n        const organizedRows = organizeRowsHierarchically(aggregatedData); // Организованные строки\n        const colCombinations = []; // Комбинации значений столбцов\n        \n        // Если есть измерения для столбцов, собираем комбинации\n        if (cols_dims.length > 0) {\n            const colMap = new Map(); // Карта для отслеживания уникальных комбинаций\n            \n            preparedData.forEach(item => {\n                const colValues = cols_dims.map(dim => item[dim]); // Значения для столбцов\n                const colKey = colValues.join('|'); // Ключ для комбинации\n                \n                // Добавляем уникальные комбинации\n                if (!colMap.has(colKey)) {\n                    colMap.set(colKey, colValues);\n                    colCombinations.push(colValues);\n                }\n            });\n            \n            // Сортируем комбинации по дате, если первое измерение - дата\n            if (cols_dims.length > 0 && isDateDimension(cols_dims[0])) {\n                colCombinations.sort((a, b) => compareDates(a[0], b[0]));\n            }\n        }\n        \n        // Собираем значения метрик для тепловой карты\n        let allMetricValues = [];\n        if (useHeatmap) {\n            const metric = metrics[0]; // Используется только первая метрика\n            \n            organizedRows.forEach(rowInfo => {\n                if (cols_dims.length === 0) {\n                    // Если нет измерений для столбцов\n                    if (rowInfo.data && rowInfo.data.columns[''] && \n                        rowInfo.data.columns[''].metrics[metric] !== undefined) {\n                        allMetricValues.push(rowInfo.data.columns[''].metrics[metric]);\n                    }\n                } else {\n                    // Если есть измерения для столбцов\n                    colCombinations.forEach(colValues => {\n                        const colKey = colValues.join('|');\n                        \n                        if (rowInfo.data && \n                            rowInfo.data.columns[colKey] && \n                            rowInfo.data.columns[colKey].metrics[metric] !== undefined) {\n                            allMetricValues.push(rowInfo.data.columns[colKey].metrics[metric]);\n                        }\n                    });\n                }\n            });\n            \n            // Фильтруем нулевые значения\n            allMetricValues = allMetricValues.filter(val => val !== null && val !== undefined);\n        }\n        \n        // Вычисляем пороговые значения для тепловой карты\n        let thresholdValue = null;\n        let maxValue = null;\n        \n        if (useHeatmap && allMetricValues.length > 0) {\n            const sortedValues = [...allMetricValues].sort((a, b) => a - b); // Сортируем значения\n            const percentileIndex = Math.floor(sortedValues.length * (1 - heatmapPercentile / 100)); // Индекс для процентиля\n            thresholdValue = sortedValues[Math.max(0, percentileIndex)]; // Пороговое значение\n            maxValue = sortedValues[sortedValues.length - 1]; // Максимальное значение\n        }\n        \n        // Заполняем строки таблицы\n        organizedRows.forEach(rowInfo => {\n            const cells = []; // Ячейки для строки\n            \n            // Добавляем значения измерений для строки\n            rowInfo.row_values.forEach((value, index) => {\n                const dim = rows_dims[index];\n                let formattedValue = value;\n                \n                // Форматируем дату, если нужно\n                if (isDateDimension(dim)) {\n                    formattedValue = formatDateTime(value, dateFormat);\n                }\n                \n                cells.push({\n                    value: value, // Исходное значение\n                    formattedValue: formattedValue, // Отформатированное значение\n                    css: { 'text-align': 'left' } // Выравнивание по левому краю\n                });\n            });\n            \n            // Если нет измерений для столбцов, добавляем метрики напрямую\n            if (cols_dims.length === 0) {\n                metrics.forEach(metric => {\n                    let value = null;\n                    \n                    // Получаем значение метрики\n                    if (rowInfo.data) {\n                        const colData = rowInfo.data.columns[''];\n                        if (colData && colData.metrics[metric] !== undefined) {\n                            value = colData.metrics[metric];\n                        }\n                    }\n                    \n                    // Форматируем значение\n                    const metric_type = metrics_defs[metric] ? metrics_defs[metric].type : 'abs';\n                    const formattedValue = nFormatter(value, 1, metric_type);\n                    \n                    // Стили для ячейки\n                    const cellCss = { \n                        'text-align': 'right' // Выравнивание по правому краю\n                    };\n                    \n                    // Добавляем цвет для тепловой карты, если нужно\n                    if (useHeatmap && value !== null && value !== undefined && value >= thresholdValue) {\n                        const normalizedValue = maxValue > thresholdValue \n                            ? (value - thresholdValue) / (maxValue - thresholdValue) // Нормализация значения\n                            : 1;\n                        \n                        // Вычисляем прозрачность для цвета\n                        let opacity = Math.round(normalizedValue * 255).toString(16).padStart(2, '0');\n                        opacity = opacity === '00' ? '01' : opacity; // Минимальная прозрачность\n                        \n                        cellCss['background-color'] = `${heatmapColor}${opacity}`; // Цвет фона с прозрачностью\n                    }\n                    \n                    // Добавляем ячейку\n                    cells.push({\n                        value: value, // Исходное значение\n                        formattedValue: formattedValue, // Отформатированное значение\n                        css: cellCss // Стили\n                    });\n                });\n            } else {\n                // Если есть измерения для столбцов, добавляем метрики для каждой комбинации столбцов\n                colCombinations.forEach(colValues => {\n                    const colKey = colValues.join('|'); // Ключ для комбинации столбцов\n                    \n                    metrics.forEach(metric => {\n                        let value = null;\n                        \n                        // Получаем значение метрики\n                        if (rowInfo.data && \n                            rowInfo.data.columns[colKey] && \n                            rowInfo.data.columns[colKey].metrics[metric] !== undefined) {\n                            value = rowInfo.data.columns[colKey].metrics[metric];\n                        }\n                        \n                        // Форматируем значение\n                        const metric_type = metrics_defs[metric] ? metrics_defs[metric].type : 'abs';\n                        const formattedValue = nFormatter(value, 1, metric_type);\n                        \n                        // Стили для ячейки\n                        const cellCss = { \n                            'text-align': 'right' // Выравнивание по правому краю\n                        };\n                        \n                        // Добавляем цвет для тепловой карты, если нужно\n                        if (useHeatmap && value !== null && value !== undefined && value >= thresholdValue) {\n                            const normalizedValue = maxValue > thresholdValue \n                                ? (value - thresholdValue) / (maxValue - thresholdValue) // Нормализация значения\n                                : 1;\n                            \n                            // Вычисляем прозрачность для цвета\n                            let opacity = Math.round(normalizedValue * 255).toString(16).padStart(2, '0');\n                            opacity = opacity === '00' ? '01' : opacity; // Минимальная прозрачность\n                            \n                            cellCss['background-color'] = `${heatmapColor}${opacity}`; // Цвет фона с прозрачностью\n                        }\n                        \n                        // Добавляем ячейку\n                        cells.push({\n                            value: value, // Исходное значение\n                            formattedValue: formattedValue, // Отформатированное значение\n                            css: cellCss // Стили\n                        });\n                    });\n                });\n            }\n            \n            // Добавляем строку в таблицу\n            rows.push({ cells });\n        });\n    }\n    function nFormatter(num, digits = 2, type = 'abs', format = 'pretty', cutZeros = true) {\n        digits = isNaN(digits) ? 2 : digits; // Проверка на корректность числа цифр\n        const sign_symb = num >= 0 ? '' : '-'; // Знак числа\n        \n        // Таблица для сокращения больших чисел\n        const lookup = [\n          { value: 0, symbol: \"\"},\n          { value: 1, symbol: \"\" },\n          { value: 1e3, symbol: \"K\" }, // Тысячи\n          { value: 1e6, symbol: \"M\" }, // Миллионы\n          { value: 1e9, symbol: \"B\" }, // Миллиарды\n          { value: 1e12, symbol: \"T\" }, // Триллионы\n          { value: 1e15, symbol: \"P\" }, // Квадриллионы\n          { value: 1e18, symbol: \"E\" }  // Квинтиллионы\n        ];\n\n        if (type === 'abs' || type === 'val') {\n            num = Math.abs(num); // Абсолютное значение\n            const rx = /\\.0+$|(\\.[0-9]*[1-9])0+$/; // Регулярное выражение для обрезки нулей\n\n            // Находим подходящую единицу измерения\n            const item = lookup.slice().reverse().find(item => num >= item.value);\n\n            if (format === 'pretty' && type !== 'val') {\n                if (item ? item.value : 0 !== 0) {\n                    // Форматируем с единицей измерения\n                    const value = `${sign_symb}${item ? (num / item.value).toFixed(digits) + item.symbol : \"0\"}`;\n                    return cutZeros ? value.replace(rx, \"$1\") : value; // Обрезаем нули, если нужно\n                } else {\n                    // Форматируем без единицы измерения\n                    const value = `${sign_symb}${item ? (num / 1).toFixed(digits) + item.symbol : \"0\"}`;\n                    return cutZeros ? value.replace(rx, \"$1\") : value; // Обрезаем нули, если нужно\n                } \n            } else {\n                // Форматируем без сокращений\n                return `${sign_symb}${item ? (num).toFixed(digits) : \"0\"}`;\n            }\n        } \n        else if (type === '%') {\n            num = Math.abs(num); // Абсолютное значение\n            // Округляем значение с учетом процента\n            const roundedNum = Math.round((num * 100 + Number.EPSILON) * Math.pow(10, digits)) / Math.pow(10, digits);\n            \n            return `${sign_symb}${roundedNum.toFixed(digits)}%`; // Форматируем как процент\n        }\n    }\n    \n    // Генерируем заголовки и заполняем строки\n    generateHeaders();\n    fillRows();\n    \n    // Возвращаем результат\n    return { head, rows };\n}\n\n// Загружаем и обрабатываем данные\nconst loadedData = Editor.getLoadedData(); // Получаем загруженные данные\nconst preparedData = Dataset.processData(loadedData, 'dataset', Editor); // Обрабатываем данные\n\n// Получаем параметры для сводной таблицы\nconst metrics_list = params.metrics_list; // Список метрик\n// Измерения для строк (до 4 измерений, пустые отфильтрованы)\nconst dimensions_rows = [params.dimension_1[0], params.dimension_2[0], params.dimension_3[0], params.dimension_4[0],params.dimension_5[0]].filter(str => str !== '');\nconst dimensions_cols = [params.dim_col1[0]]; // Измерение для столбцов\n\n// Создаем и возвращаем сводную таблицу\nmodule.exports = createPivotTable(preparedData, dimensions_rows, dimensions_cols, metrics_list, params);\n","sources":"const {buildSource} = require('libs/dataset/v2');\nconst {dateTimeParse,dateTime,addDays, addUnits,startOf} = require('@gravity-ui/date-utils');\nconst FORMAT = 'YYYY-MM-DD'\n\n\nfunction arrayChecker(some) {\n    if (Array.isArray(some)) {\n        return some\n    }\n    else {\n        return [some]\n        }\n}\n\n\nfunction getDateFilters(ce_obj,params) {\n    let date_interval = params.date_interval[0];\n    let date_dim = params.filter_date_dimension[0];\n    let scale_name = params.date_scale[0];\n        let scale_dict = {'day':'D','week':'W','month':'M'};\n\n    const {from:from_date,to:to_date} = ce_obj.resolveInterval(date_interval);\n    let right_date = to_date;\n    let left_date = from_date;\n    const dateTo = dateTimeParse(right_date).add(1,scale_name).startOf(scale_dict[scale_name]).add(-1,'day').format(FORMAT);\n    const dateFrom = dateTimeParse(left_date).startOf(scale_dict[scale_name]).format(FORMAT);\n\n    const dateFilter = {column: date_dim,\n                            operation: 'BETWEEN',\n                        values: [dateFrom, dateTo]}\n    return dateFilter;\n}\n\n\nconst params = Editor.getParams();\n// для удобства все параметры переносим в переменные без парамс\nconst date_interval = params.date_interval[0];\nconst limit = parseInt(params.row_limit[0]);\nconst metrics_list = params.metrics_list;\nconst params_to_send = params.params_to_send[0];\nconst filter_fields = params.filter_fields_ids['0'].split('|');\nconst filter_mass = params.mass_filter_fields_ids['0'].split('|');\n\n// массив для заполнения условий\nlet where = [];\n// колонки для выбора\nlet cols = [];\n// передавать параметры в датасет\nlet filled_params = []\n\n// 1) add date interval filter\nlet date_where = Editor.resolveInterval(date_interval);\nlet val = [date_where['from'],date_where['to']];\n\nlet q = getDateFilters(Editor,params);\n\nwhere.push(q)\n\nfor (const [key, value] of Object.entries(params)) {\n    // добавляем все параметры из переданных и не пустых\n    if (params_to_send.includes(key)) {\n      filled_params.push({id:key,value:value.toString()});\n    };\n\n    if (filter_fields.includes(key) && value != '') {\n            let val, suff;\n\n\n        if (value[0] && value[0].substr(0, 2) === '__') {\n            const {operation:suffx, value:vala} = Editor.resolveOperation(value);\n            console.log(suffx,vala)\n            val = vala;\n            suff = suffx;\n\n        } else {\n            val = value;\n            suff = 'IN';\n        }\n\n\n        if  (Editor.resolveRelative(val) != null) {\n              val = Editor.resolveRelative(val);\n         }\n        if  (Editor.resolveInterval(value) != null) {\n              val = [Editor.resolveInterval(value)['from'],Editor.resolveInterval(value)['to']];\n              suff = 'BETWEEN'\n         }\n\n        if  (filter_mass.includes(key)) {\n        suff = 'IN';\n        val = value[0].split(' ');\n    }\n     \n    where.push({type:'id',column: key, operation: suff, values: arrayChecker(val)})\n  }\n  \n      if ((key.startsWith('dimension_') || key.startsWith('dim_col'))  && value[0] != '') {\n            cols.push(value[0]);\n    }\n\n}\n\n// добавляем колонки для выбора данных\ncols.push(...metrics_list);\n\n\nmodule.exports = {\n        dataset: buildSource({\n            id: Editor.getId('dataset'),\n            columns: cols,\n            where: where,\n            parameters:filled_params,\n            order:params.date_dimension[0],\n            limit:limit*2,\n            order_by:[{'direction':'DESC','column':metrics_list[0]}]\n        })\n    }\n","controls":"module.exports = {};"},"name":"0. Edit Chart with AI","type":"table_node","annotation":{"description":""}}},"6":{"widget":{"data":{"meta":"{\n    \"links\": {\n        \"dataset\": \"4\"\n    }\n}","params":"module.exports = {\n\n    // Тут надо перечислить поля, которые будут участвовать в фильтрации из датасета, для этого в датасете нажмите \"показать id\" и скопируйте их сюда\n    // Следите за актуализацией id полей при их изменении в датасете!\n    filter_fields_ids:['deliverytype_heh6|paymenttype_kig4|gender_ezzk|orderid_oakw'],\n    // Передача массового значения из эксель, например, и подстановка в IN оператор, влияет положительно на производительность\n    // Не используйте длинные значения параметров, т.к. можно выйти за лимит длины строки, поддерживаемый браузером!\n    // Следите за актуализацией id полей при их изменении в датасете\n    mass_filter_fields_ids:['orderid_oakw'],\n    // Список метрик к отрисовке, для self-service анализа заводите как параметр ручного ввода на дашборд\n    // Не используйте длинные значения параметров, т.к. можно выйти за лимит длины строки, поддерживаемый браузером!\n    metrics_list:['GMV','AOV'],\n    // Тут в виде JSON должны быть описаны метрики, это требуется, чтобы можно было понять, как какую метрику рисовать, в абсолютах, в процентах\n    // Имейте в виду, что символы экранируются, постарайтесь избегать различных спец-символов\n    // Не используйте длинные значения параметров, т.к. можно выйти за лимит длины строки, поддерживаемый браузером!\n    // Следите за актуализацией id полей при их изменении в датасете\n    metrics_defs:[`{\"GMV\":{\"description\":\"Gross Merchandise Volume\",\"type\":\"abs\"},\"AOV\":{\"description\":\"Average Order Value\",\"type\":\"abs\"}}`],\n    // Параметр ручного ввода ввести на дашборде - он автоматически свяжется\n    date_interval:['__interval_2024-08-12T00:00:00.000Z_2024-08-18T00:00:00.000Z'],\n    // Параметр ручного ввода ввести на дашборде - он автоматически свяжется\n    date_scale:['week'],\n    // Поле, которое имеет формулу DATETRUNC([some_date],[date_scale]) для приведения к началу периода\n    // Следите за актуализацией id полей при их изменении в датасете\n    date_dimension:['Date scaled'],\n    // Поле для фильтра данных в таблице, не равно полю с приведением к началу месяца, чтобы можно было оптимально выбирать данные\n    // Следите за актуализацией id полей при их изменении в датасете\n    filter_date_dimension:['creation_dt'],\n    // Сколько строк выбирать из источника LIMIT\n    params_to_send:['date_scale|'],\n    // Что показывать в отклонениях, лучше вывести как параметр на дашбдорд, значения abs, %, both\n    pop_type:['abs'],\n    // С каким днем сравнивать \n    day_wow:['7'],\n \n \n    font_size:['14px'],\n    dec_num:['1']\n};\n","prepare":"const Dataset = require('libs/dataset/v2');\n\nconst params = Editor.getParams();\nconst metrics_list = params.metrics_list;\nconst metrics_params = JSON.parse(params.metrics_defs[0]);\n\n\n// Обработка данных\nconst total_data = Dataset.getDatasetRows({datasetName: 'dataset'});\nconst dynamic_data = Dataset.getDatasetRows({datasetName: 'dataset_dynamic'});\n\nconsole.log(\n'//const total_data = ' + JSON.stringify(total_data) + ';' +\n'\\n//const dynamic_data = ' + JSON.stringify(dynamic_data)+';' +\n'\\n//nmetrics_params = ' + params.metrics_defs[0]+ ';' +\n'\\n//nmetrics_list = ' + JSON.stringify(params.metrics_list) + ';'\n)","sources":"const { buildSource } = require('libs/dataset/v2');\nconst { dateTimeParse } = require('@gravity-ui/date-utils');\nconst FORMAT = 'YYYY-MM-DD';\n\nconst params = Editor.getParams();\n\n// Для удобства все параметры переносим в переменные без params\nconst date_interval = params.date_interval[0];\nconst metrics_list = params.metrics_list;\nconst params_to_send = params.params_to_send[0];\nconst filter_fields = params.filter_fields_ids['0'].split('|');\nconst filter_mass = params.mass_filter_fields_ids['0'].split('|');\n\n/**\n * Преобразует значение в массив, если оно им не является\n * @param {*} value - Значение для проверки\n * @returns {Array} - Массив\n */\nfunction ensureArray(value) {\n    return Array.isArray(value) ? value : [value];\n}\n\n/**\n * Получает фильтр дат для PoP (Period over Period) сравнения\n * @param {Object} params - Параметры\n * @returns {Object} - Объект фильтра дат\n */\nfunction getDateFilterPoP(params) {\n    const date_dim = params.filter_date_dimension[0];\n    const scale_name = params.date_scale[0];\n\n    const {from:from_date, to: to_date } = Editor.resolveInterval(date_interval);\n    const right_date = to_date;\n\n    let    dateFilter = {\n            column: date_dim,\n            operation: 'BETWEEN',\n            values: [from_date, to_date],\n        };\n    \n\n    return dateFilter;\n}\n\n\n// Массив для заполнения условий фильтрации\nconst where = [];\n// Колонки для выбора\nconst cols = [];\n// Параметры для передачи в датасет\nconst filled_params = [];\n\n// 1) Добавляем фильтр дат для PoP (Period over Period) сравнения\nwhere.push(getDateFilterPoP(params));\n\n// Обрабатываем все параметры\nfor (const [key, value] of Object.entries(params)) {\n    // Добавляем все параметры из переданных и не пустых\n    if (params_to_send.includes(key)) {\n        filled_params.push({ id: key, value: value.toString() });\n    }\n\n    // Обрабатываем фильтры\n    if (filter_fields.includes(key) && value !== '') {\n        let val, suff;\n\n        // Проверяем формат входных данных\n        if (value[0] && value[0].substr(0, 2) === '__') {\n            const {operation:suffx, value:vala} = Editor.resolveOperation(value);\n            val = vala;\n            suff = suffx;\n\n        } else {\n            val = value;\n            suff = 'IN';\n        }\n\n        // Проверяем и преобразуем относительные даты\n        if (Editor.resolveRelative(val) != null) {\n            val = Editor.resolveRelative(val);\n        }\n\n        // Проверяем и преобразуем интервалы\n        if (Editor.resolveInterval(value) != null) {\n            val = [Editor.resolveInterval(value)['from'], Editor.resolveInterval(value)['to']];\n            suff = 'BETWEEN';\n        }\n\n        //Проверяем фильтры с массовыми значениями\n        if (filter_mass.includes(key)) {\n            suff = 'IN';\n            val = value[0].split(' ');\n        }\n        \n        // Добавляем условие в массив where\n        where.push({\n            type: 'id',\n            column: key,\n            operation: suff,\n            values: ensureArray(val)\n        });\n    }\n\n    // Добавляем измерения в колонки\n    if (key.startsWith('dimension_') && value[0] !== '') {\n        cols.push(value[0]);\n    }\n}\n\n// Добавляем метрики в колонки\ncols.push(...metrics_list);\n\n\n\n// Экспортируем настройки для buildSource\nmodule.exports = {\n    dataset: buildSource({\n        id: Editor.getId(\"dataset\"),\n        columns: cols,\n        where: where,\n        parameters: filled_params,\n        order: params.date_dimension[0],\n        order_by: [{ 'direction': 'DESC', 'column': metrics_list[0] }],\n    }),\n        dataset_dynamic: buildSource({\n        id: Editor.getId(\"dataset\"),\n        columns: [...cols,'Date scaled'],\n        where: where,\n        parameters: filled_params,\n        order: params.date_dimension[0],\n        order_by: [{ 'direction': 'DESC', 'column': metrics_list[0] }],\n    })\n};\n","controls":"module.exports = {};\n"},"name":"1. AI Chart","type":"advanced-chart_node","annotation":{"description":""}}},"9":{"widget":{"data":{"meta":"{\n    \"links\": {\n        \"dataset\": \"0\"\n    }\n}","params":"module.exports = {\n\n};\n","prepare":"const Dataset = require('libs/dataset/v2');\n\nconst params = Editor.getParams();\n\n\n// Обработка данных\nconst full_data = Dataset.getDatasetRows({datasetName: 'dataset'});\n\n\n//const full_data = [{\"stage_id\":\"1\",\"stage_name\":\"Миссия `Мяутоматизация`: запуск котофабрики будущего\",\"start_dt\":\"2025-01-15\",\"duration\":\"180\",\"prevous_stage_id\":\"\",\"executor_login\":\"project_manager\"},{\"stage_id\":\"10\",\"stage_name\":\"Распространение механического мурчания по всему миру\",\"start_dt\":\"\",\"duration\":\"90\",\"prevous_stage_id\":\"9\",\"executor_login\":\"sales_team\"},{\"stage_id\":\"11\",\"stage_name\":\"Операция `Умная голова в песке`: создание говорящих страусов\",\"start_dt\":\"2025-03-15\",\"duration\":\"210\",\"prevous_stage_id\":\"\",\"executor_login\":\"project_manager\"},{\"stage_id\":\"12\",\"stage_name\":\"Научить ИИ прятать голову при сложных вопросах как настоящий эксперт\",\"start_dt\":\"\",\"duration\":\"60\",\"prevous_stage_id\":\"11\",\"executor_login\":\"ai_team\"},{\"stage_id\":\"13\",\"stage_name\":\"Конструирование металлоперьевых несушек смысла\",\"start_dt\":\"\",\"duration\":\"45\",\"prevous_stage_id\":\"11\",\"executor_login\":\"mechanical_engineers\"},{\"stage_id\":\"14\",\"stage_name\":\"Сборка первого страуса, который знает всё и ничего одновременно\",\"start_dt\":\"\",\"duration\":\"50\",\"prevous_stage_id\":\"12,13\",\"executor_login\":\"prototype_team\"},{\"stage_id\":\"15\",\"stage_name\":\"Вживление словарей в механические перья\",\"start_dt\":\"\",\"duration\":\"40\",\"prevous_stage_id\":\"14\",\"executor_login\":\"hardware_team\"},{\"stage_id\":\"16\",\"stage_name\":\"Обучение страуса говорить умными фразами в неподходящий момент\",\"start_dt\":\"\",\"duration\":\"35\",\"prevous_stage_id\":\"14\",\"executor_login\":\"software_team\"},{\"stage_id\":\"17\",\"stage_name\":\"Проектирование инкубатора для искусственного интеллекта\",\"start_dt\":\"\",\"duration\":\"30\",\"prevous_stage_id\":\"11\",\"executor_login\":\"planning_team\"},{\"stage_id\":\"18\",\"stage_name\":\"Монтаж гнезд для кремниевых яиц мудрости\",\"start_dt\":\"\",\"duration\":\"60\",\"prevous_stage_id\":\"15,17\",\"executor_login\":\"installation_team\"},{\"stage_id\":\"19\",\"stage_name\":\"Создание академии для птиц, которые умнее своих создателей\",\"start_dt\":\"\",\"duration\":\"40\",\"prevous_stage_id\":\"16,18\",\"executor_login\":\"training_team\"},{\"stage_id\":\"2\",\"stage_name\":\"Выяснение, сколько котиков человечеству не хватает для полного счастья\",\"start_dt\":\"\",\"duration\":\"30\",\"prevous_stage_id\":\"1\",\"executor_login\":\"marketing_team\"},{\"stage_id\":\"20\",\"stage_name\":\"Торжественный выпуск первой партии пернатых философов\",\"start_dt\":\"\",\"duration\":\"30\",\"prevous_stage_id\":\"19\",\"executor_login\":\"operations_team\"},{\"stage_id\":\"21\",\"stage_name\":\"Расселение умных страусов среди обычных людей\",\"start_dt\":\"\",\"duration\":\"45\",\"prevous_stage_id\":\"20\",\"executor_login\":\"distribution_team\"},{\"stage_id\":\"22\",\"stage_name\":\"Миссия `Вкус разочарования`: попкорн, который не оправдает никаких надежд\",\"start_dt\":\"2025-09-16\",\"duration\":\"150\",\"prevous_stage_id\":\"\",\"executor_login\":\"product_owner\"}];","sources":"const { buildSource } = require('libs/dataset/v2');\n\n// Экспортируем настройки для buildSource\nmodule.exports = {\n    dataset: buildSource({\n        id: Editor.getId(\"dataset\"),\n        columns: [\"stage_id\",\"stage_name\",\"start_dt\",\"duration\",\"prevous_stage_id\",\"executor_login\"],\n        order_by: [{ 'direction': 'ASC', 'column': 'stage_id' }],\n    })\n};\n","controls":"module.exports = {};\n"},"name":"2. AI Gantt Chart","type":"advanced-chart_node","annotation":{"description":""}}},"10":{"widget":{"data":{"meta":"{\n    \"links\": {\n        \"dataset\": \"0\"\n    }\n}","config":"module.exports = {\n\n};\n","params":"module.exports = {\n\n};\n","prepare":"const Dataset = require('libs/dataset/v2');\n\nconst params = Editor.getParams();\n\n\n// Обработка данных\nconst full_data = Dataset.getDatasetRows({datasetName: 'dataset'});\n\n\n//const full_data = [{\"stage_id\":\"1\",\"stage_name\":\"Миссия `Мяутоматизация`: запуск котофабрики будущего\",\"start_dt\":\"2025-01-15\",\"duration\":\"180\",\"prevous_stage_id\":\"\",\"executor_login\":\"project_manager\"},{\"stage_id\":\"10\",\"stage_name\":\"Распространение механического мурчания по всему миру\",\"start_dt\":\"\",\"duration\":\"90\",\"prevous_stage_id\":\"9\",\"executor_login\":\"sales_team\"},{\"stage_id\":\"11\",\"stage_name\":\"Операция `Умная голова в песке`: создание говорящих страусов\",\"start_dt\":\"2025-03-15\",\"duration\":\"210\",\"prevous_stage_id\":\"\",\"executor_login\":\"project_manager\"},{\"stage_id\":\"12\",\"stage_name\":\"Научить ИИ прятать голову при сложных вопросах как настоящий эксперт\",\"start_dt\":\"\",\"duration\":\"60\",\"prevous_stage_id\":\"11\",\"executor_login\":\"ai_team\"},{\"stage_id\":\"13\",\"stage_name\":\"Конструирование металлоперьевых несушек смысла\",\"start_dt\":\"\",\"duration\":\"45\",\"prevous_stage_id\":\"11\",\"executor_login\":\"mechanical_engineers\"},{\"stage_id\":\"14\",\"stage_name\":\"Сборка первого страуса, который знает всё и ничего одновременно\",\"start_dt\":\"\",\"duration\":\"50\",\"prevous_stage_id\":\"12,13\",\"executor_login\":\"prototype_team\"},{\"stage_id\":\"15\",\"stage_name\":\"Вживление словарей в механические перья\",\"start_dt\":\"\",\"duration\":\"40\",\"prevous_stage_id\":\"14\",\"executor_login\":\"hardware_team\"},{\"stage_id\":\"16\",\"stage_name\":\"Обучение страуса говорить умными фразами в неподходящий момент\",\"start_dt\":\"\",\"duration\":\"35\",\"prevous_stage_id\":\"14\",\"executor_login\":\"software_team\"},{\"stage_id\":\"17\",\"stage_name\":\"Проектирование инкубатора для искусственного интеллекта\",\"start_dt\":\"\",\"duration\":\"30\",\"prevous_stage_id\":\"11\",\"executor_login\":\"planning_team\"},{\"stage_id\":\"18\",\"stage_name\":\"Монтаж гнезд для кремниевых яиц мудрости\",\"start_dt\":\"\",\"duration\":\"60\",\"prevous_stage_id\":\"15,17\",\"executor_login\":\"installation_team\"},{\"stage_id\":\"19\",\"stage_name\":\"Создание академии для птиц, которые умнее своих создателей\",\"start_dt\":\"\",\"duration\":\"40\",\"prevous_stage_id\":\"16,18\",\"executor_login\":\"training_team\"},{\"stage_id\":\"2\",\"stage_name\":\"Выяснение, сколько котиков человечеству не хватает для полного счастья\",\"start_dt\":\"\",\"duration\":\"30\",\"prevous_stage_id\":\"1\",\"executor_login\":\"marketing_team\"},{\"stage_id\":\"20\",\"stage_name\":\"Торжественный выпуск первой партии пернатых философов\",\"start_dt\":\"\",\"duration\":\"30\",\"prevous_stage_id\":\"19\",\"executor_login\":\"operations_team\"},{\"stage_id\":\"21\",\"stage_name\":\"Расселение умных страусов среди обычных людей\",\"start_dt\":\"\",\"duration\":\"45\",\"prevous_stage_id\":\"20\",\"executor_login\":\"distribution_team\"},{\"stage_id\":\"22\",\"stage_name\":\"Миссия `Вкус разочарования`: попкорн, который не оправдает никаких надежд\",\"start_dt\":\"2025-09-16\",\"duration\":\"150\",\"prevous_stage_id\":\"\",\"executor_login\":\"product_owner\"}];","sources":"const { buildSource } = require('libs/dataset/v2');\n\n// Экспортируем настройки для buildSource\nmodule.exports = {\n    dataset: buildSource({\n        id: Editor.getId(\"dataset\"),\n        columns: [\"stage_id\",\"stage_name\",\"start_dt\",\"duration\",\"prevous_stage_id\",\"executor_login\"],\n        order_by: [{ 'direction': 'ASC', 'column': 'stage_id' }],\n    })\n};\n","controls":"module.exports = {};"},"name":"3  AI Gantt in Table","type":"table_node","annotation":{"description":""}}}},"connection":{"8":{"connection":{"host":"rc1d-qcq36mub1a2sqn69.mdb.yandexcloud.net","name":"CH AI Editor Demo","port":8443,"secure":"on","db_name":null,"db_type":"clickhouse","password":"secure_password","readonly":2,"username":"db2_reader","description":"","workbook_id":"stwdv05018vid","cache_ttl_sec":0,"mdb_folder_id":null,"raw_sql_level":"dashsql","mdb_cluster_id":null,"data_export_forbidden":"off","connection_manager_cloud_id":null,"connection_manager_folder_id":null,"connection_manager_connection_id":null,"connection_manager_delegation_is_set":null}}},"dataset":{"0":{"dataset":{"name":"Gantt Dataset","rls2":{},"sources":[{"id":"e872e041-92f9-11f0-a18b-95ed66e718fa","title":"SQL","valid":true,"virtual":false,"managed_by":"user","parameters":{"subsql":"select * from s3('https://storage.yandexcloud.net/skaradubpics/cocktails/projects.csv')"},"raw_schema":[{"name":"stage_id","title":"stage_id","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":true,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"stage_name","title":"stage_name","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":true,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"start_dt","title":"start_dt","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":true,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"duration","title":"duration","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":true,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"prevous_stage_id","title":"prevous_stage_id","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":true,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"executor_login","title":"executor_login","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":true,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false}],"source_type":"CH_SUBSELECT","connection_id":"8","index_info_set":null,"parameter_hash":"e0ec555b9c7b9264"}],"description":"","revision_id":null,"result_schema":[{"cast":"string","guid":"stage_id_7g83","type":"DIMENSION","title":"stage_id","valid":true,"hidden":false,"source":"stage_id","formula":"","virtual":false,"avatar_id":"e872e040-92f9-11f0-a18b-95ed66e718fa","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"stage_name_4y6k","type":"DIMENSION","title":"stage_name","valid":true,"hidden":false,"source":"stage_name","formula":"","virtual":false,"avatar_id":"e872e040-92f9-11f0-a18b-95ed66e718fa","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"start_dt_9fn0","type":"DIMENSION","title":"start_dt","valid":true,"hidden":false,"source":"start_dt","formula":"","virtual":false,"avatar_id":"e872e040-92f9-11f0-a18b-95ed66e718fa","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"duration_078y","type":"DIMENSION","title":"duration","valid":true,"hidden":false,"source":"duration","formula":"","virtual":false,"avatar_id":"e872e040-92f9-11f0-a18b-95ed66e718fa","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"prevous_stage_id_3oli","type":"DIMENSION","title":"prevous_stage_id","valid":true,"hidden":false,"source":"prevous_stage_id","formula":"","virtual":false,"avatar_id":"e872e040-92f9-11f0-a18b-95ed66e718fa","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"executor_login_odi7","type":"DIMENSION","title":"executor_login","valid":true,"hidden":false,"source":"executor_login","formula":"","virtual":false,"avatar_id":"e872e040-92f9-11f0-a18b-95ed66e718fa","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false}],"source_avatars":[{"id":"e872e040-92f9-11f0-a18b-95ed66e718fa","title":"SQL","valid":true,"is_root":true,"virtual":false,"source_id":"e872e041-92f9-11f0-a18b-95ed66e718fa","managed_by":"user"}],"preview_enabled":true,"avatar_relations":[],"component_errors":{"items":[]},"template_enabled":false,"result_schema_aux":{"inter_dependencies":{"deps":[]}},"obligatory_filters":[],"data_export_forbidden":false,"load_preview_by_default":true}},"4":{"dataset":{"name":"MarketPlace AI Demo","rls2":{},"sources":[{"id":"953b7f51-6ed1-11f0-bc0b-9f4f042ada30","title":"orders_lc","valid":true,"virtual":false,"managed_by":"user","parameters":{"db_name":"db2","db_version":"25.3.6.56","table_name":"orders_lc"},"raw_schema":[{"name":"category_level_1","title":"category_level_1","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"category_level_2","title":"category_level_2","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"category_level_3","title":"category_level_3","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"region_delivery","title":"region_delivery","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"city_delivery","title":"city_delivery","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"delivery_type","title":"delivery_type","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"delivery_service","title":"delivery_service","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"sku_color","title":"sku_color","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"user_gender","title":"user_gender","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"user_platform","title":"user_platform","nullable":true,"user_type":"string","description":"","native_type":{"name":"string","nullable":false,"lowcardinality":true,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"user_id","title":"user_id","nullable":true,"user_type":"integer","description":"","native_type":{"name":"uint64","nullable":false,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"order_id","title":"order_id","nullable":true,"user_type":"integer","description":"","native_type":{"name":"uint64","nullable":false,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"creation_dt","title":"creation_dt","nullable":true,"user_type":"genericdatetime","description":"","native_type":{"name":"datetimewithtz","nullable":false,"timezone_name":"Europe/Moscow","lowcardinality":false,"explicit_timezone":false,"native_type_class_name":"clickhouse_datetimewithtz_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"delivery_dt","title":"delivery_dt","nullable":true,"user_type":"genericdatetime","description":"","native_type":{"name":"datetimewithtz","nullable":false,"timezone_name":"Europe/Moscow","lowcardinality":false,"explicit_timezone":false,"native_type_class_name":"clickhouse_datetimewithtz_native_type"},"lock_aggregation":false,"has_auto_aggregation":false},{"name":"amount","title":"amount","nullable":true,"user_type":"float","description":"","native_type":{"name":"float64","nullable":false,"lowcardinality":false,"native_type_class_name":"clickhouse_native_type"},"lock_aggregation":false,"has_auto_aggregation":false}],"source_type":"CH_TABLE","connection_id":"8","index_info_set":null,"parameter_hash":"a4368992e6943c51"}],"description":"","revision_id":null,"result_schema":[{"cast":"integer","guid":"78cf2b50-8ca9-11f0-a219-ffe370dfee11","type":"MEASURE","title":"Orders","valid":true,"hidden":false,"source":"","formula":"COUNTD_APPROX([order_id])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"integer","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"COUNTD_APPROX([order_id_iejj])","default_value":null,"autoaggregated":true,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"integer","aggregation_locked":true,"has_auto_aggregation":true},{"cast":"float","guid":"374b78a0-8ca9-11f0-a219-ffe370dfee11","type":"MEASURE","title":"AOV","valid":true,"hidden":false,"source":"","formula":"sum([amount])/COUNTD_APPROX([order_id])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"float","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"sum([amount_52rb])/COUNTD_APPROX([order_id_iejj])","default_value":null,"autoaggregated":true,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"float","aggregation_locked":true,"has_auto_aggregation":true},{"cast":"genericdatetime","guid":"a939feb0-8ca8-11f0-a219-ffe370dfee11","type":"DIMENSION","title":"Date scaled","valid":true,"hidden":false,"source":"","formula":"DATETRUNC([delivery_dt],[date_scale])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"genericdatetime","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"DATETRUNC([delivery_dt_y2sz],[date_scale])","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"genericdatetime","aggregation_locked":true,"has_auto_aggregation":false},{"cast":"string","guid":"date_scale","type":"DIMENSION","title":"date_scale","valid":true,"hidden":false,"source":"","formula":"","virtual":false,"avatar_id":null,"calc_mode":"parameter","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":"week","autoaggregated":false,"lock_aggregation":false,"template_enabled":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":true,"has_auto_aggregation":false},{"cast":"float","guid":"de256650-710a-11f0-a040-7f2cfa045483","type":"MEASURE","title":"GMV","valid":true,"hidden":false,"source":"","formula":"sum([amount])","virtual":false,"avatar_id":null,"calc_mode":"formula","data_type":"float","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"sum([amount_52rb])","default_value":null,"autoaggregated":true,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"float","aggregation_locked":true,"has_auto_aggregation":true},{"cast":"string","guid":"category_level_1_n71b","type":"DIMENSION","title":"category_level_1","valid":true,"hidden":false,"source":"category_level_1","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"category_level_2_exd4","type":"DIMENSION","title":"category_level_2","valid":true,"hidden":false,"source":"category_level_2","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"category_level_3_50lm","type":"DIMENSION","title":"category_level_3","valid":true,"hidden":false,"source":"category_level_3","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"region_delivery_efn9","type":"DIMENSION","title":"region_delivery","valid":true,"hidden":false,"source":"region_delivery","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"city_delivery_ho3c","type":"DIMENSION","title":"city_delivery","valid":true,"hidden":false,"source":"city_delivery","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"delivery_type_juix","type":"DIMENSION","title":"delivery_type","valid":true,"hidden":false,"source":"delivery_type","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"delivery_service_blbn","type":"DIMENSION","title":"delivery_service","valid":true,"hidden":false,"source":"delivery_service","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"sku_color_xokm","type":"DIMENSION","title":"sku_color","valid":true,"hidden":false,"source":"sku_color","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"user_gender_fqvv","type":"DIMENSION","title":"user_gender","valid":true,"hidden":false,"source":"user_gender","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"string","guid":"user_platform_rhsy","type":"DIMENSION","title":"user_platform","valid":true,"hidden":false,"source":"user_platform","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"string","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"string","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"integer","guid":"user_id_9k0n","type":"DIMENSION","title":"user_id","valid":true,"hidden":false,"source":"user_id","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"integer","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"integer","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"integer","guid":"order_id_iejj","type":"DIMENSION","title":"order_id","valid":true,"hidden":false,"source":"order_id","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"integer","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"integer","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"genericdatetime","guid":"creation_dt_4enj","type":"DIMENSION","title":"creation_dt","valid":true,"hidden":false,"source":"creation_dt","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"genericdatetime","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"genericdatetime","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"genericdatetime","guid":"delivery_dt_y2sz","type":"DIMENSION","title":"delivery_dt","valid":true,"hidden":false,"source":"delivery_dt","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"genericdatetime","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"genericdatetime","aggregation_locked":false,"has_auto_aggregation":false},{"cast":"float","guid":"amount_52rb","type":"DIMENSION","title":"amount","valid":true,"hidden":false,"source":"amount","formula":"","virtual":false,"avatar_id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","calc_mode":"direct","data_type":"float","managed_by":"user","aggregation":"none","description":"","ui_settings":"","guid_formula":"","default_value":null,"autoaggregated":false,"lock_aggregation":false,"value_constraint":null,"initial_data_type":"float","aggregation_locked":false,"has_auto_aggregation":false}],"source_avatars":[{"id":"953b7f50-6ed1-11f0-bc0b-9f4f042ada30","title":"db2.orders_lc","valid":true,"is_root":true,"virtual":false,"source_id":"953b7f51-6ed1-11f0-bc0b-9f4f042ada30","managed_by":"user"}],"preview_enabled":true,"avatar_relations":[],"component_errors":{"items":[]},"template_enabled":false,"result_schema_aux":{"inter_dependencies":{"deps":[{"dep_field_id":"de256650-710a-11f0-a040-7f2cfa045483","ref_field_ids":["amount_52rb"]},{"dep_field_id":"a939feb0-8ca8-11f0-a219-ffe370dfee11","ref_field_ids":["date_scale","delivery_dt_y2sz"]},{"dep_field_id":"374b78a0-8ca9-11f0-a219-ffe370dfee11","ref_field_ids":["order_id_iejj","amount_52rb"]},{"dep_field_id":"78cf2b50-8ca9-11f0-a219-ffe370dfee11","ref_field_ids":["order_id_iejj"]}]}},"obligatory_filters":[],"data_export_forbidden":false,"load_preview_by_default":true}}},"dash":{"7":{"dash":{"data":{"salt":"0.3480960843773757","tabs":[{"id":"LA","items":[{"id":"yG","data":{"tabs":[{"id":"Ez","hint":"","title":"Dynamic_line","params":{},"chartId":"1","isDefault":true,"autoHeight":false,"background":{"color":"transparent"},"enableHint":false,"description":"","enableDescription":false}],"hideTitle":true},"type":"widget","namespace":"default"},{"id":"jy","data":{"tabs":[{"id":"1J","hint":"","title":"finance_header","params":{"title":["Вайб-чартинг в DataLens Editor"]},"chartId":"2","isDefault":true,"autoHeight":false,"background":{"color":"transparent"},"enableHint":false,"description":"","enableDescription":false}],"hideTitle":true},"type":"widget","namespace":"default"},{"id":"xm","data":{"tabs":[{"id":"Gz","hint":"","title":"Indicator","params":{},"chartId":"3","isDefault":true,"autoHeight":false,"background":{"color":"transparent"},"enableHint":false,"description":"","enableDescription":false}],"hideTitle":true},"type":"widget","namespace":"default"},{"id":"0A","data":{"tabs":[{"id":"r6","hint":"","title":"AI Chart 1","params":{},"chartId":"6","isDefault":true,"autoHeight":false,"background":{"color":"transparent"},"enableHint":false,"description":"","enableDescription":false}],"hideTitle":false},"type":"widget","namespace":"default"},{"id":"98","data":{"group":[{"id":"ae","title":"Период","width":"","source":{"isRange":true,"required":false,"showHint":false,"fieldName":"date_interval","showTitle":true,"accentType":null,"elementType":"date","defaultValue":"__interval_2024-08-05T00:00:00.000Z_2024-09-09T00:00:00.000Z","titlePlacement":"left"},"defaults":{"date_interval":"__interval_2024-08-05T00:00:00.000Z_2024-09-09T00:00:00.000Z"},"namespace":"default","sourceType":"manual","placementMode":"auto"}],"autoHeight":false,"buttonApply":false,"buttonReset":false,"showGroupName":false,"updateControlsOnChange":false},"type":"group_control","namespace":"default"},{"id":"6j","data":{"text":"","autoHeight":false,"background":{"color":"","enabled":true}},"type":"text","namespace":"default"},{"id":"N9","data":{"group":[{"id":"OK","title":"Масштаб","width":"","source":{"required":false,"showHint":false,"fieldName":"date_scale","showTitle":true,"accentType":null,"elementType":"select","defaultValue":["week"],"titlePlacement":"left","acceptableValues":[{"title":"month","value":"month"},{"title":"day","value":"day"},{"title":"week","value":"week"}]},"defaults":{"date_scale":["week"]},"namespace":"default","sourceType":"manual","placementMode":"auto"}],"autoHeight":false,"buttonApply":false,"buttonReset":false,"showGroupName":false,"updateControlsOnChange":false},"type":"group_control","namespace":"default"}],"title":"Main","layout":[{"h":8,"i":"yG","w":11,"x":0,"y":9},{"h":3,"i":"jy","w":36,"x":0,"y":0},{"h":4,"i":"xm","w":11,"x":0,"y":5},{"h":12,"i":"0A","w":12,"x":11,"y":5},{"h":2,"i":"98","w":11,"x":0,"y":3},{"h":2,"i":"6j","w":17,"x":19,"y":3},{"h":2,"i":"N9","w":8,"x":11,"y":3}],"aliases":{"default":[["creation_dt_4enj","date_interval"]]},"connections":[{"to":"Ez","from":"ae","kind":"ignore"}]},{"id":"We","items":[{"id":"gM","data":{"text":"## AI Chart 2\n\n```\n# Задача\nу тебя в getCurrentCodePrompt описаны 4 массива с метриками их описанием и значениями тотал и по дням, придумай сам и напиши код, который будет показывать каждую из этих метрик в виде большого числа и детальные данные внутри красивой и понятной плитики (плитка вниз или вправо заложено в коде) числа должна быть отформатированы до 1 знака и размерности указаны 1 буквой, форматирование всех чисел сделай до передачи в render\n\nна детальных графиках должен быть тултип на точках\n\n\n# ОГРАНИЧЕНИЯ РАБОТЫ!!\n- никакие атрибуты для передачи информации кроме data-id не разрешены.\n- с датами работай как со строками, не используй библиотеки по работе с данными, просто обрезай 10 символов.\n- не забывай, клики и тултипы можно только через renderer делать\n- в значении data-id используй _ для разделителя\n- чтобы линии встраивались в график используй preserveAspectRatio=\"none\"\n```","autoHeight":false,"background":{"color":"like-chart-bg","enabled":true}},"type":"text","namespace":"default"},{"id":"o8","data":{"text":"## Что любит моделька в промпте?\n\n- Маркдаун (как средство деления задачи на блоки)\n\n- Если нужно что-то усилить - используйте bold (\\*\\*text\\*\\*)\n\n- Примеры и контр-примеры кода\n\n- Цифры, которые помогут модели лучше понять логику\n\n- Раздел с ограничениями по коду\n\n## Что делать, если не все сразу получилось?\n\n- уточнять конкретные моменты в диалоге, чтобы программа исправилась\n\n- Лучше найти все недочеты и спрашивать один раз\n\n- Много исправлений делать не надо - сохраните чарт и начните новый диалог","autoHeight":false,"background":{"color":"like-chart-bg","enabled":true}},"type":"text","namespace":"default"},{"id":"mO","data":{"text":"## AI Chart 1\n\n```\nCделай перевод заголовков метрик следующим образом:\nесли параметр params.lang[0] равен en, то в заголовок метрики брать alias_en, иначе просто alias\n\nВозврати только ту измененную функцию, которая требуется\n```","autoHeight":false,"background":{"color":"like-chart-bg","enabled":true}},"type":"text","namespace":"default"}],"title":"Prompts","layout":[{"h":16,"i":"gM","w":17,"x":0,"y":16},{"h":16,"i":"o8","w":19,"x":17,"y":0},{"h":16,"i":"mO","w":17,"x":0,"y":0}],"aliases":{},"connections":[]}],"counter":18,"settings":{"hideTabs":false,"expandTOC":false,"globalParams":{},"loadPriority":"charts","hideDashTitle":true,"silentLoading":false,"autoupdateInterval":null,"dependentSelectors":true,"loadOnlyVisibleCharts":true,"maxConcurrentRequests":null},"schemeVersion":8,"accessDescription":"","supportDescription":""},"name":"Editor AI Workshop","annotation":{"description":""}}}}}},"hash":"2bbdab9a2950be3aaaa2cc8083801d2404b705486a3fef026baf90c5a5cf600d"}