UNPKG

@finos/legend-data-cube

Version:
163 lines 27.9 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { observer } from 'mobx-react-lite'; import { cn, DataCubeIcon, useDropdownMenu } from '@finos/legend-art'; import { DataCubeFont, DataCubeFontCase, DataCubeFontFormatUnderlineVariant, DataCubeFontTextAlignment, DataCubeQuerySortDirection, DEFAULT_BACKGROUND_COLOR, DEFAULT_ERROR_FOREGROUND_COLOR, DEFAULT_FOREGROUND_COLOR, DEFAULT_GRID_LINE_COLOR, DEFAULT_NEGATIVE_FOREGROUND_COLOR, DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR, DEFAULT_ZERO_FOREGROUND_COLOR, EMPTY_VALUE_PLACEHOLDER, } from '../../../stores/core/DataCubeQueryEngine.js'; import { FormCheckbox, FormColorPickerButton, FormDropdownMenu, FormDropdownMenuItem, FormDropdownMenuItemSeparator, FormDropdownMenuTrigger, FormTextInput, FormNumberInput, FormBadge_WIP, FormDocumentation, FormButton, } from '../../core/DataCubeFormUtils.js'; import { DataCubeDocumentationKey } from '../../../__lib__/DataCubeDocumentation.js'; export const DataCubeEditorGeneralPropertiesPanel = observer((props) => { const { view } = props; const panel = view.editor.generalProperties; const configuration = panel.configuration; const [openTreeColumnSortOperatorDropdown, closeTreeColumnSortOperatorDropdown, treeColumnSortOperatorDropdownProps, treeColumnSortOperatorDropdownPropsOpen,] = useDropdownMenu(); const [openInitialExpandLevelDropdown, closeInitialExpandLevelDropdown, initialExpandLevelDropdownProps, initialExpandLevelDropdownPropsOpen,] = useDropdownMenu(); const [openFontFamilyDropdown, closeFontFamilyDropdown, fontFamilyDropdownProps, fontFamilyDropdownPropsOpen,] = useDropdownMenu(); const [openFontSizeDropdown, closeFontSizeDropdown, openFontSizeDropdownProps, openFontSizeDropdownPropsOpen,] = useDropdownMenu(); const [openFontFormatUnderlineVariantDropdown, closeFontFormatUnderlineVariantDropdown, fontFormatUnderlineVariantDropdownProps,] = useDropdownMenu(); const [openFontCaseDropdown, closeFontCaseDropdown, fontCaseDropdownProps] = useDropdownMenu(); return (_jsxs("div", { className: "h-full w-full select-none p-2", children: [_jsxs("div", { className: "flex h-6", children: [_jsx("div", { className: "flex h-6 items-center text-xl font-medium", children: _jsx(DataCubeIcon.TableOptions, {}) }), _jsx("div", { className: "ml-1 flex h-6 items-center text-xl font-medium", children: "General Properties" })] }), _jsx("div", { className: "flex h-[calc(100%_-_24px)] w-full", children: _jsxs("div", { className: "h-full w-full py-2", children: [_jsxs("div", { className: "flex h-6 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: "Report Title:" }), _jsx(FormTextInput, { className: "h-6 w-96 text-lg font-semibold", value: configuration.name, onChange: (event) => { configuration.setName(event.target.value); } })] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: "Tree Column:" }), _jsx(FormCheckbox, { label: "Show root aggregation", checked: configuration.showRootAggregation, onChange: () => configuration.setShowRootAggregation(!configuration.showRootAggregation) }), _jsx(FormCheckbox, { className: "ml-3", label: "Show leaf count", checked: configuration.showLeafCount, onChange: () => configuration.setShowLeafCount(!configuration.showLeafCount) })] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm" }), _jsx("div", { className: "mr-1 flex h-full flex-shrink-0 items-center text-sm", children: "Sort:" }), _jsx(FormDropdownMenuTrigger, { className: "w-20", onClick: openTreeColumnSortOperatorDropdown, open: treeColumnSortOperatorDropdownPropsOpen, children: configuration.treeColumnSortDirection }), _jsx(FormDropdownMenu, { className: "w-20", ...treeColumnSortOperatorDropdownProps, children: [ DataCubeQuerySortDirection.ASCENDING, DataCubeQuerySortDirection.DESCENDING, ].map((direction) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setTreeColumnSortDirection(direction); closeTreeColumnSortOperatorDropdown(); }, autoFocus: direction === configuration.treeColumnSortDirection, children: direction }, direction))) }), _jsx("div", { className: "ml-3 mr-1 flex h-full flex-shrink-0 items-center text-sm", children: "Initially expand to level:" }), _jsx(FormDropdownMenuTrigger, { className: "w-16", onClick: openInitialExpandLevelDropdown, open: initialExpandLevelDropdownPropsOpen, showAsPlaceholder: configuration.initialExpandLevel === undefined, children: configuration.initialExpandLevel ?? EMPTY_VALUE_PLACEHOLDER }), _jsx(FormDropdownMenu, { className: "w-16", ...initialExpandLevelDropdownProps, children: [undefined, 1, 2, 3, 4, 5, 6, 7, 8].map((level) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setInitialExpandLevel(level); closeInitialExpandLevelDropdown(); }, autoFocus: level === configuration.initialExpandLevel, children: level ?? EMPTY_VALUE_PLACEHOLDER }, level ?? ''))) })] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsxs("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: ["Row Limit:", _jsx(FormDocumentation, { className: "ml-1", documentationKey: DataCubeDocumentationKey.GRID_CONFIGURATION_ROW_LIMIT })] }), _jsx(FormNumberInput, { className: "w-16 text-sm", value: panel.limit, min: 0, step: 1, defaultValue: undefined, placeholder: EMPTY_VALUE_PLACEHOLDER, setValue: (value) => panel.setLimit(value) })] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm" }), _jsx(FormCheckbox, { label: "Display warning when truncated", checked: configuration.showWarningForTruncatedResult, onChange: () => configuration.setShowWarningForTruncatedResult(!configuration.showWarningForTruncatedResult) })] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: "Show Selection Stats?" }), _jsx(FormCheckbox, { checked: configuration.showSelectionStats, onChange: () => configuration.setShowSelectionStats(!configuration.showSelectionStats), disabled: true }), _jsx(FormBadge_WIP, {})] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: "Show Lines?" }), _jsx(FormCheckbox, { label: "Horizontal", checked: configuration.showHorizontalGridLines, onChange: () => configuration.setShowHorizontalGridLines(!configuration.showHorizontalGridLines) }), _jsx(FormCheckbox, { className: "ml-3", label: "Vertical", checked: configuration.showVerticalGridLines, onChange: () => configuration.setShowVerticalGridLines(!configuration.showVerticalGridLines) }), _jsx("div", { className: "ml-3 mr-1 flex h-full flex-shrink-0 items-center text-sm", children: "Color:" }), _jsx(FormColorPickerButton, { color: configuration.gridLineColor, defaultColor: DEFAULT_GRID_LINE_COLOR, onChange: (value) => configuration.setGridLineColor(value) })] }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: "Hightlight Rows:" }), _jsx(FormCheckbox, { label: "Standard mode", checked: configuration.alternateRowsStandardMode, onChange: () => { if (configuration.alternateRowsStandardMode) { configuration.setAlternateRowsStandardMode(false); } else { configuration.setAlternateRowsStandardMode(true); configuration.setAlternateRows(false); } } }), _jsx(FormCheckbox, { className: "ml-3", checked: configuration.alternateRows, onChange: () => { if (configuration.alternateRows) { configuration.setAlternateRows(false); } else { configuration.setAlternateRows(true); configuration.setAlternateRowsStandardMode(false); } } }), _jsx("div", { className: "ml-1 mr-1 flex h-full flex-shrink-0 items-center text-sm", children: "Custom: Alternate color:" }), _jsx(FormColorPickerButton, { disabled: !configuration.alternateRows, color: configuration.alternateRowsColor, defaultColor: DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR, onChange: (value) => configuration.setAlternateRowsColor(value) }), _jsx("div", { className: "ml-1 flex h-full flex-shrink-0 items-center text-sm", children: "every:" }), _jsx(FormNumberInput, { className: "ml-1 w-16 text-sm", disabled: !configuration.alternateRows, min: 1, step: 1, defaultValue: 1, isValid: (value) => value !== undefined && value > 0, value: configuration.alternateRowsCount, setValue: (value) => configuration.setAlternateRowsCount(value ?? 1) }), _jsx("div", { className: "ml-1 flex-shrink-0 text-sm", children: "rows" })] }), _jsx("div", { className: "my-2 h-[1px] w-full bg-neutral-200" }), _jsxs("div", { className: "mt-2 flex h-5 w-full items-center", children: [_jsx("div", { className: "flex h-full w-32 flex-shrink-0 items-center text-sm", children: "Default Font:" }), _jsx(FormDropdownMenuTrigger, { className: "w-28", onClick: openFontFamilyDropdown, open: fontFamilyDropdownPropsOpen, children: configuration.fontFamily }), _jsxs(FormDropdownMenu, { className: "w-28", ...fontFamilyDropdownProps, children: [[ DataCubeFont.ARIAL, DataCubeFont.ROBOTO, DataCubeFont.ROBOTO_CONDENSED, ].map((font) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setFontFamily(font); closeFontFamilyDropdown(); }, autoFocus: font === configuration.fontFamily, children: font }, font))), _jsx(FormDropdownMenuItemSeparator, {}), [ DataCubeFont.GEORGIA, DataCubeFont.ROBOTO_SERIF, DataCubeFont.TIMES_NEW_ROMAN, ].map((font) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setFontFamily(font); closeFontFamilyDropdown(); }, autoFocus: font === configuration.fontFamily, children: font }, font))), _jsx(FormDropdownMenuItemSeparator, {}), [ DataCubeFont.JERBRAINS_MONO, DataCubeFont.ROBOTO_MONO, DataCubeFont.UBUNTU_MONO, ].map((font) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setFontFamily(font); closeFontFamilyDropdown(); }, autoFocus: font === configuration.fontFamily, children: font }, font)))] }), _jsx(FormDropdownMenuTrigger, { className: "ml-1 w-10", onClick: openFontSizeDropdown, open: openFontSizeDropdownPropsOpen, children: configuration.fontSize }), _jsx(FormDropdownMenu, { className: "w-10", ...openFontSizeDropdownProps, children: [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 48, 72, ].map((size) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setFontSize(size); closeFontSizeDropdown(); }, autoFocus: size === configuration.fontSize, children: size }, size))) }), _jsxs("div", { className: "relative ml-2 flex h-5", children: [_jsx("button", { title: "Bold", className: cn('relative flex h-5 w-5 items-center justify-center rounded-bl-sm rounded-tl-sm border border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.fontBold, }), onClick: () => configuration.setFontBold(!configuration.fontBold), children: _jsx(DataCubeIcon.FontBold, {}) }), _jsx("button", { title: "Italic", className: cn('relative -ml-[1px] flex h-5 w-5 items-center justify-center border border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.fontItalic, }), onClick: () => configuration.setFontItalic(!configuration.fontItalic), children: _jsx(DataCubeIcon.FontItalic, {}) }), _jsx("button", { title: `Underline${configuration.fontUnderline ? ` (${configuration.fontUnderline})` : ''}`, className: cn('relative -ml-[1px] flex h-5 w-5 items-center justify-center border border-r-0 border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.fontUnderline !== undefined, }), onClick: () => { if (configuration.fontUnderline === undefined) { configuration.setFontUnderline(DataCubeFontFormatUnderlineVariant.SOLID); configuration.setFontStrikethrough(false); } else { configuration.setFontUnderline(undefined); } }, children: _jsx(DataCubeIcon.FontUnderline, {}) }), _jsxs("button", { className: "text-2xs relative -ml-[1px] flex h-5 w-2.5 items-center justify-center border border-l-0 border-neutral-400 bg-neutral-50 p-0 text-neutral-600 focus:z-[1]", onClick: openFontFormatUnderlineVariantDropdown, children: [_jsx("div", { className: cn('h-4 w-[0.5px] bg-neutral-200', { 'opacity-0': configuration.fontUnderline !== undefined, }) }), _jsx(DataCubeIcon.CaretDown, {})] }), _jsx(FormDropdownMenu, { className: "w-14", ...fontFormatUnderlineVariantDropdownProps, children: [ DataCubeFontFormatUnderlineVariant.SOLID, DataCubeFontFormatUnderlineVariant.DASHED, DataCubeFontFormatUnderlineVariant.DOTTED, DataCubeFontFormatUnderlineVariant.DOUBLE, DataCubeFontFormatUnderlineVariant.WAVY, ].map((variant) => (_jsx(FormDropdownMenuItem, { className: "relative", onClick: () => { configuration.setFontUnderline(variant); configuration.setFontStrikethrough(false); closeFontFormatUnderlineVariantDropdown(); }, autoFocus: variant === configuration.fontUnderline, children: _jsx("div", { className: cn('!hover:underline absolute top-0 !underline', { '!hover:decoration-solid !decoration-solid': variant === DataCubeFontFormatUnderlineVariant.SOLID, '!hover:decoration-dashed !decoration-dashed': variant === DataCubeFontFormatUnderlineVariant.DASHED, '!hover:decoration-dotted !decoration-dotted': variant === DataCubeFontFormatUnderlineVariant.DOTTED, '!hover:decoration-double !decoration-double': variant === DataCubeFontFormatUnderlineVariant.DOUBLE, '!hover:decoration-wavy !decoration-wavy': variant === DataCubeFontFormatUnderlineVariant.WAVY, }), children: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0" }) }, variant))) }), _jsx("button", { title: "Strikethrough", className: cn('relative -ml-[1px] flex h-5 w-5 items-center justify-center border border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.fontStrikethrough, }), onClick: () => { if (configuration.fontStrikethrough) { configuration.setFontStrikethrough(false); } else { configuration.setFontStrikethrough(true); configuration.setFontUnderline(undefined); } }, children: _jsx(DataCubeIcon.FontStrikethrough, {}) }), _jsx("button", { title: `Case${configuration.fontCase ? ` (${configuration.fontCase})` : ''}`, className: cn('relative -ml-[1px] flex h-5 w-5 items-center justify-center border border-r-0 border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.fontCase !== undefined, }), onClick: () => { configuration.setFontCase(configuration.fontCase === undefined ? DataCubeFontCase.UPPERCASE : undefined); }, children: _jsx(DataCubeIcon.FontCase, { className: "stroke-[0.5px]" }) }), _jsxs("button", { className: "text-2xs relative -ml-[1px] flex h-5 w-2.5 items-center justify-center rounded-br-sm rounded-tr-sm border border-l-0 border-neutral-400 bg-neutral-50 p-0 text-neutral-600 focus:z-[1]", onClick: openFontCaseDropdown, children: [_jsx("div", { className: cn('h-4 w-[0.5px] bg-neutral-200', { 'opacity-0': configuration.fontCase !== undefined, }) }), _jsx(DataCubeIcon.CaretDown, {})] }), _jsx(FormDropdownMenu, { className: "w-20", ...fontCaseDropdownProps, children: [ DataCubeFontCase.LOWERCASE, DataCubeFontCase.UPPERCASE, DataCubeFontCase.CAPITALIZE, ].map((fontCase) => (_jsx(FormDropdownMenuItem, { onClick: () => { configuration.setFontCase(fontCase); closeFontCaseDropdown(); }, autoFocus: fontCase === configuration.fontCase, children: _jsx("div", { className: cn({ lowercase: fontCase === DataCubeFontCase.LOWERCASE, uppercase: fontCase === DataCubeFontCase.UPPERCASE, capitalize: fontCase === DataCubeFontCase.CAPITALIZE, }), children: fontCase }) }, fontCase))) })] }), _jsxs("div", { className: "relative ml-2 flex h-5", children: [_jsx("button", { title: "Align Left", className: cn('relative flex h-5 w-5 items-center justify-center rounded-bl-sm rounded-tl-sm border border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.textAlign === DataCubeFontTextAlignment.LEFT, }), onClick: () => configuration.setTextAlign(DataCubeFontTextAlignment.LEFT), children: _jsx(DataCubeIcon.TextAlignLeft, {}) }), _jsx("button", { title: "Align Center", className: cn('relative -ml-[1px] flex h-5 w-5 items-center justify-center border border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.textAlign === DataCubeFontTextAlignment.CENTER, }), onClick: () => configuration.setTextAlign(DataCubeFontTextAlignment.CENTER), children: _jsx(DataCubeIcon.TextAlignCenter, {}) }), _jsx("button", { title: "Align Right", className: cn('relative -ml-[1px] flex h-5 w-5 items-center justify-center rounded-br-sm rounded-tr-sm border border-neutral-400 bg-neutral-50 p-0 text-neutral-700 focus:z-[1]', { 'bg-neutral-200': configuration.textAlign === DataCubeFontTextAlignment.RIGHT, }), onClick: () => configuration.setTextAlign(DataCubeFontTextAlignment.RIGHT), children: _jsx(DataCubeIcon.TextAlignRight, {}) })] })] }), _jsxs("div", { className: "mt-2 flex w-full", children: [_jsx("div", { className: "flex h-6 w-32 flex-shrink-0 items-center text-sm", children: "Default Colors:" }), _jsxs("div", { className: "h-18", children: [_jsxs("div", { className: "flex h-6", children: [_jsx("div", { className: "w-16 flex-shrink-0" }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center text-sm", children: "Normal" }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center text-sm", children: "Negative" }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center text-sm", children: "Zero" }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center text-sm", children: "Error" })] }), _jsxs("div", { className: "flex h-6", children: [_jsx("div", { className: "flex h-full w-16 flex-shrink-0 items-center text-sm", children: "Foreground:" }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.normalForegroundColor, defaultColor: DEFAULT_FOREGROUND_COLOR, onChange: (value) => configuration.setNormalForegroundColor(value) }) }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.negativeForegroundColor, defaultColor: DEFAULT_NEGATIVE_FOREGROUND_COLOR, onChange: (value) => configuration.setNegativeForegroundColor(value) }) }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.zeroForegroundColor, defaultColor: DEFAULT_ZERO_FOREGROUND_COLOR, onChange: (value) => configuration.setZeroForegroundColor(value) }) }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.errorForegroundColor, defaultColor: DEFAULT_ERROR_FOREGROUND_COLOR, onChange: (value) => configuration.setErrorForegroundColor(value) }) })] }), _jsxs("div", { className: "flex h-6", children: [_jsx("div", { className: "flex h-full w-16 flex-shrink-0 items-center text-sm", children: "Background:" }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.normalBackgroundColor, defaultColor: DEFAULT_BACKGROUND_COLOR, onChange: (value) => configuration.setNormalBackgroundColor(value) }) }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.negativeBackgroundColor, defaultColor: DEFAULT_BACKGROUND_COLOR, onChange: (value) => configuration.setNegativeBackgroundColor(value) }) }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.zeroBackgroundColor, defaultColor: DEFAULT_BACKGROUND_COLOR, onChange: (value) => configuration.setZeroBackgroundColor(value) }) }), _jsx("div", { className: "flex h-full w-12 flex-shrink-0 items-center justify-center", children: _jsx(FormColorPickerButton, { color: configuration.errorBackgroundColor, defaultColor: DEFAULT_BACKGROUND_COLOR, onChange: (value) => configuration.setErrorBackgroundColor(value) }) })] })] })] }), _jsxs("div", { className: "mt-2 flex w-full", children: [_jsx("div", { className: "flex h-6 w-32 flex-shrink-0 items-center text-sm" }), _jsxs("div", { className: "w-80", children: [_jsx("div", { className: "mb-2 h-[1px] w-full bg-neutral-200" }), _jsx(FormButton, { compact: true, disabled: configuration.isUsingDefaultStyling, onClick: () => configuration.useDefaultStyling(), children: "Use Default Styling" })] })] })] }) })] })); }); //# sourceMappingURL=DataCubeEditorGeneralPropertiesPanel.js.map