├── .editorconfig
├── .git-blame-ignore-revs
├── .github
├── chart-builder.png
├── frappe-logo.svg
├── helpers
│ └── install_dependencies.sh
├── hero-image-v2.png
├── hero-image.png
├── join-editor.png
├── logo.png
├── new-logo.svg
├── preview.gif
├── query-builder.png
├── query-view.png
├── result-view.png
├── try-on-fc.svg
├── visualize-view.png
└── workflows
│ ├── build.yml
│ ├── make-release-pr.yml
│ ├── playwright.yml
│ ├── release.yml
│ └── server-tests.yml
├── .gitignore
├── .gitmodules
├── .pre-commit-config.yaml
├── .releaserc
├── MANIFEST.in
├── README.md
├── docker
├── docker-compose.yml
└── init.sh
├── flake8
├── frontend
├── .eslintrc.json
├── .gitignore
├── .prettierrc.json
├── README.md
├── components.d.ts
├── index.html
├── index_v2.html
├── package.json
├── playwright.config.js
├── postcss.config.js
├── public
│ ├── favicon.png
│ └── insights-logo.png
├── src
│ ├── App.vue
│ ├── api
│ │ ├── index.ts
│ │ └── whitelistedMethods.ts
│ ├── assets
│ │ ├── ERPNextIcon.png
│ │ ├── FiraCode
│ │ │ ├── FiraCode-Bold.woff
│ │ │ ├── FiraCode-Bold.woff2
│ │ │ ├── FiraCode-Light.woff
│ │ │ ├── FiraCode-Light.woff2
│ │ │ ├── FiraCode-Medium.woff
│ │ │ ├── FiraCode-Medium.woff2
│ │ │ ├── FiraCode-Regular.woff
│ │ │ ├── FiraCode-Regular.woff2
│ │ │ ├── FiraCode-SemiBold.woff
│ │ │ ├── FiraCode-SemiBold.woff2
│ │ │ ├── FiraCode-VF.woff
│ │ │ ├── FiraCode-VF.woff2
│ │ │ └── fira_code.css
│ │ ├── Inter
│ │ │ ├── Inter-Black.woff
│ │ │ ├── Inter-Black.woff2
│ │ │ ├── Inter-BlackItalic.woff
│ │ │ ├── Inter-BlackItalic.woff2
│ │ │ ├── Inter-Bold.woff
│ │ │ ├── Inter-Bold.woff2
│ │ │ ├── Inter-BoldItalic.woff
│ │ │ ├── Inter-BoldItalic.woff2
│ │ │ ├── Inter-ExtraBold.woff
│ │ │ ├── Inter-ExtraBold.woff2
│ │ │ ├── Inter-ExtraBoldItalic.woff
│ │ │ ├── Inter-ExtraBoldItalic.woff2
│ │ │ ├── Inter-ExtraLight.woff
│ │ │ ├── Inter-ExtraLight.woff2
│ │ │ ├── Inter-ExtraLightItalic.woff
│ │ │ ├── Inter-ExtraLightItalic.woff2
│ │ │ ├── Inter-Italic.woff
│ │ │ ├── Inter-Italic.woff2
│ │ │ ├── Inter-Light.woff
│ │ │ ├── Inter-Light.woff2
│ │ │ ├── Inter-LightItalic.woff
│ │ │ ├── Inter-LightItalic.woff2
│ │ │ ├── Inter-Medium.woff
│ │ │ ├── Inter-Medium.woff2
│ │ │ ├── Inter-MediumItalic.woff
│ │ │ ├── Inter-MediumItalic.woff2
│ │ │ ├── Inter-Regular.woff
│ │ │ ├── Inter-Regular.woff2
│ │ │ ├── Inter-SemiBold.woff
│ │ │ ├── Inter-SemiBold.woff2
│ │ │ ├── Inter-SemiBoldItalic.woff
│ │ │ ├── Inter-SemiBoldItalic.woff2
│ │ │ ├── Inter-Thin.woff
│ │ │ ├── Inter-Thin.woff2
│ │ │ ├── Inter-ThinItalic.woff
│ │ │ ├── Inter-ThinItalic.woff2
│ │ │ ├── Inter-italic.var.woff2
│ │ │ ├── Inter-roman.var.woff2
│ │ │ ├── Inter.var.woff2
│ │ │ └── inter.css
│ │ ├── MariaDBIcon.png
│ │ ├── PostgreSQLIcon.png
│ │ ├── SampleDataIcon.png
│ │ ├── SheetIcon.png
│ │ ├── add-data-source-new.mp4
│ │ ├── add-data-source.mp4
│ │ ├── build-first-query-new.mp4
│ │ ├── build-first-query.mp4
│ │ ├── create-first-dashboard-new.mp4
│ │ ├── create-first-dashboard.mp4
│ │ ├── frappe-framework-logo.svg
│ │ ├── insights-icon.svg
│ │ ├── insights-logo-new.svg
│ │ └── insights-logo.svg
│ ├── components
│ │ ├── AppShell.vue
│ │ ├── BasePage.vue
│ │ ├── Breadcrumbs.vue
│ │ ├── Charts
│ │ │ ├── BaseChart.vue
│ │ │ └── ChartTitle.vue
│ │ ├── CommandPalette.vue
│ │ ├── ContentEditable.vue
│ │ ├── Controls
│ │ │ ├── Attachment.vue
│ │ │ ├── Autocomplete.vue
│ │ │ ├── Checkbox.vue
│ │ │ ├── Code.vue
│ │ │ ├── ColorInput.vue
│ │ │ ├── ColorPalette.vue
│ │ │ ├── ColorPicker.vue
│ │ │ ├── DatePicker.vue
│ │ │ ├── DatePickerFlat.vue
│ │ │ ├── DateRangePicker.vue
│ │ │ ├── DateRangePickerFlat.vue
│ │ │ ├── InputWithTabs.vue
│ │ │ ├── LinkIcon.vue
│ │ │ ├── ListPicker.vue
│ │ │ ├── TimespanPicker.vue
│ │ │ └── TimespanPickerFlat.vue
│ │ ├── DraggableList.vue
│ │ ├── DraggableListItemMenu.vue
│ │ ├── ExpressionHelp.vue
│ │ ├── Grid.vue
│ │ ├── HelpDialog.vue
│ │ ├── Icons
│ │ │ ├── ComboChartIcon.vue
│ │ │ ├── DragHandleIcon.vue
│ │ │ ├── FrappeLogo.vue
│ │ │ ├── HomeIcon.vue
│ │ │ ├── IndicatorIcon.vue
│ │ │ ├── JoinFullIcon.vue
│ │ │ ├── JoinInnerIcon.vue
│ │ │ ├── JoinLeftIcon.vue
│ │ │ └── JoinRightIcon.vue
│ │ ├── ListFilter
│ │ │ ├── FilterIcon.vue
│ │ │ ├── ListFilter.vue
│ │ │ ├── NestedPopover.vue
│ │ │ └── SearchComplete.vue
│ │ ├── LoginBox.vue
│ │ ├── NewDialogWithTypes.vue
│ │ ├── PageBreadcrumbs.vue
│ │ ├── PageTitle.vue
│ │ ├── Popover.vue
│ │ ├── PublicShareDialog.vue
│ │ ├── ResizeableInput.vue
│ │ ├── Setting.vue
│ │ ├── ShareDialog.vue
│ │ ├── Sidebar.vue
│ │ ├── SuspenseFallback.jsx
│ │ ├── Table
│ │ │ ├── TableColumnFilter.vue
│ │ │ ├── TableEmpty.vue
│ │ │ ├── TableGroupedCell.vue
│ │ │ ├── TableLinkCell.vue
│ │ │ ├── TableNumberCell.vue
│ │ │ ├── TanstackTable.vue
│ │ │ └── utils.js
│ │ ├── Tabs.vue
│ │ ├── Toast.vue
│ │ ├── Topbar.vue
│ │ ├── UsePopover.vue
│ │ └── UseTooltip.vue
│ ├── dashboard
│ │ ├── Dashboard.vue
│ │ ├── DashboardEmptyState.vue
│ │ ├── DashboardItem.vue
│ │ ├── DashboardItemActions.vue
│ │ ├── DashboardList.vue
│ │ ├── DashboardListCard.vue
│ │ ├── DashboardListGroup.vue
│ │ ├── DashboardMenuButton.vue
│ │ ├── DashboardNavbarButtons.vue
│ │ ├── DashboardQueryDialog.vue
│ │ ├── DashboardQueryEditor.vue
│ │ ├── DashboardQueryOption.vue
│ │ ├── DashboardShareButton.vue
│ │ ├── DashboardWidgetsOptions.vue
│ │ ├── PublicDashboard.vue
│ │ ├── PublicDashboardItem.vue
│ │ ├── SimpleFilter.vue
│ │ ├── UseDropZone.vue
│ │ ├── VueGridLayout.vue
│ │ ├── useDashboard.js
│ │ ├── useDashboards.js
│ │ └── usePublicDashboard.js
│ ├── datasource
│ │ ├── ConnectMariaDBDialog.vue
│ │ ├── ConnectPostgreDBDialog.vue
│ │ ├── DataSource.vue
│ │ ├── DataSourceList.vue
│ │ ├── DataSourceRelationships.vue
│ │ ├── DataSourceTable.vue
│ │ ├── DataSourceTableColumnHeader.vue
│ │ ├── FileSourceForm.vue
│ │ ├── MariaDBForm.vue
│ │ ├── PostgreSQLForm.vue
│ │ ├── SampleDatasetList.vue
│ │ ├── TableEdge.vue
│ │ ├── TableNode.vue
│ │ ├── TableRelationshipEditor.vue
│ │ ├── UploadCSVFileDialog.vue
│ │ ├── useDataSource.ts
│ │ └── useDataSourceTable.ts
│ ├── global.d.ts
│ ├── globals.js
│ ├── home
│ │ ├── Home.vue
│ │ ├── HomeOnboarding.vue
│ │ ├── HomePinnedItems.vue
│ │ ├── HomeQuickActions.vue
│ │ ├── HomeRecentRecords.vue
│ │ └── ProgressRing.vue
│ ├── index.css
│ ├── layouts
│ │ └── BaseLayout.vue
│ ├── main.js
│ ├── notebook
│ │ ├── Notebook.vue
│ │ ├── NotebookList.vue
│ │ ├── NotebookPage.vue
│ │ ├── NotebookPageDropdown.vue
│ │ ├── blocks
│ │ │ ├── BlockAction.vue
│ │ │ ├── BlockActions.vue
│ │ │ ├── chart
│ │ │ │ ├── ChartBlock.vue
│ │ │ │ ├── ChartOptions.vue
│ │ │ │ └── ChartOptionsDropdown.vue
│ │ │ └── query
│ │ │ │ ├── QueryBlock.vue
│ │ │ │ └── QueryBlockHeader.vue
│ │ ├── tiptap
│ │ │ ├── TipTap.vue
│ │ │ ├── extensions
│ │ │ │ ├── Chart.js
│ │ │ │ ├── Chart.vue
│ │ │ │ ├── Query.vue
│ │ │ │ ├── QueryEditor.js
│ │ │ │ └── utils.js
│ │ │ └── slash-command
│ │ │ │ ├── CommandsList.vue
│ │ │ │ ├── commands.js
│ │ │ │ └── suggestion.js
│ │ ├── useNotebook.js
│ │ ├── useNotebookPage.js
│ │ └── useNotebooks.js
│ ├── pages
│ │ ├── AddTeamDialog.vue
│ │ ├── AddUserDialog.vue
│ │ ├── Avatars.vue
│ │ ├── Form.vue
│ │ ├── Login.vue
│ │ ├── ManageTeamDialog.vue
│ │ ├── ManageTeamMembers.vue
│ │ ├── ManageTeamResourceAccess.vue
│ │ ├── ManageTeamSidebar.vue
│ │ ├── NoPermission.vue
│ │ ├── NotFound.vue
│ │ ├── Settings.vue
│ │ ├── Teams.vue
│ │ ├── TrialExpired.vue
│ │ └── Users.vue
│ ├── query
│ │ ├── ChartActionButtons.vue
│ │ ├── ChartOptions.vue
│ │ ├── ChartSection.vue
│ │ ├── ChartSectionEmptySvg.vue
│ │ ├── ChartTypeSelector.vue
│ │ ├── ExpressionHelpDialog.vue
│ │ ├── NativeQueryBuilder.vue
│ │ ├── NativeQueryEditor.vue
│ │ ├── PublicChart.vue
│ │ ├── Query.vue
│ │ ├── QueryDataSourceSelector.vue
│ │ ├── QueryHeader.vue
│ │ ├── QueryHeaderTitle.vue
│ │ ├── QueryList.vue
│ │ ├── QueryMenu.vue
│ │ ├── ResultSection.vue
│ │ ├── SchemaExplorerDialog.vue
│ │ ├── ScriptQueryEditor.vue
│ │ ├── VariablesDialog.vue
│ │ ├── deprecated
│ │ │ ├── ClassicQueryBuilder.vue
│ │ │ ├── Column
│ │ │ │ ├── ColumnEditor.vue
│ │ │ │ ├── ColumnExpressionPicker.vue
│ │ │ │ ├── ColumnList.vue
│ │ │ │ ├── ColumnPanel.vue
│ │ │ │ ├── ColumnPicker.vue
│ │ │ │ └── SimpleColumnPicker.vue
│ │ │ ├── Filter
│ │ │ │ ├── BinaryExpression.vue
│ │ │ │ ├── CallExpression.vue
│ │ │ │ ├── Expression.vue
│ │ │ │ ├── ExpressionTerm.vue
│ │ │ │ ├── FilterExpressionPicker.vue
│ │ │ │ ├── FilterPanel.vue
│ │ │ │ ├── FilterPicker.vue
│ │ │ │ ├── LogicalExpression.vue
│ │ │ │ └── SimpleFilterPicker.vue
│ │ │ ├── LimitsAndOrder.vue
│ │ │ └── Table
│ │ │ │ ├── TableJoiner.vue
│ │ │ │ └── TablePanel.vue
│ │ ├── resources
│ │ │ ├── useQuery.js
│ │ │ ├── useQueryChart.js
│ │ │ └── useQueryResults.js
│ │ ├── useChart.js
│ │ ├── usePublicChart.js
│ │ ├── useQueryResource.js
│ │ └── visual
│ │ │ ├── ColumnExpressionEditor.vue
│ │ │ ├── ColumnListItem.vue
│ │ │ ├── ColumnSection.vue
│ │ │ ├── CumulativeSumTransformFields.vue
│ │ │ ├── ExpressionBuilder.vue
│ │ │ ├── FilterEditor.vue
│ │ │ ├── FilterListItem.vue
│ │ │ ├── FilterSection.vue
│ │ │ ├── FilterValueSelector.vue
│ │ │ ├── LimitSection.vue
│ │ │ ├── PivotTransformFields.vue
│ │ │ ├── ResultColumnActions.vue
│ │ │ ├── ResultFooter.vue
│ │ │ ├── SectionHeader.vue
│ │ │ ├── SimpleColumnEditor.vue
│ │ │ ├── SourceSection.vue
│ │ │ ├── TableJoinEditor.vue
│ │ │ ├── TableSection.vue
│ │ │ ├── TransformEditor.vue
│ │ │ ├── TransformListItem.vue
│ │ │ ├── TransformSection.vue
│ │ │ ├── VisualQueryBuilder.vue
│ │ │ ├── constants.js
│ │ │ ├── messages.js
│ │ │ ├── useAssistedQuery.js
│ │ │ └── utils.js
│ ├── router.ts
│ ├── setup
│ │ ├── Setup.vue
│ │ ├── SetupQuestions.vue
│ │ ├── SourceConnectionStep.vue
│ │ └── SourceTypeStep.vue
│ ├── socket.js
│ ├── stores
│ │ ├── cacheStore.ts
│ │ ├── dataSourceStore.ts
│ │ ├── queryStore.ts
│ │ ├── sessionStore.ts
│ │ ├── settingsStore.ts
│ │ └── setupStore.ts
│ ├── subscription
│ │ └── index.js
│ ├── utils
│ │ ├── colors.ts
│ │ ├── commandPalette.js
│ │ ├── dayjs.js
│ │ ├── expressions
│ │ │ ├── filter.js
│ │ │ ├── index.js
│ │ │ └── tokenize.js
│ │ ├── format.js
│ │ ├── index.js
│ │ ├── prompt.js
│ │ ├── query
│ │ │ ├── columns.js
│ │ │ ├── filters.js
│ │ │ ├── index.js
│ │ │ ├── results.js
│ │ │ └── tables.js
│ │ ├── resizer.js
│ │ ├── systemSettings.js
│ │ ├── telemetry.js
│ │ ├── toasts.js
│ │ ├── transitions.js
│ │ ├── useTeams.js
│ │ └── useUsers.js
│ ├── vite-end.d.ts
│ └── widgets
│ │ ├── AxisChart
│ │ ├── AxisChartOptions.vue
│ │ └── getAxisChartOptions.js
│ │ ├── Bar
│ │ ├── Bar.vue
│ │ ├── BarOptions.vue
│ │ └── getBarChartOptions.js
│ │ ├── Filter
│ │ ├── Filter.vue
│ │ └── FilterOptions.vue
│ │ ├── Funnel
│ │ ├── Funnel.vue
│ │ ├── FunnelOptions.vue
│ │ └── getFunnelChartOptions.js
│ │ ├── InvalidWidget.vue
│ │ ├── Line
│ │ ├── Line.vue
│ │ ├── LineOptions.vue
│ │ └── getLineChartOptions.js
│ │ ├── MixedAxis
│ │ ├── MixedAxis.vue
│ │ ├── MixedAxisOptions.vue
│ │ └── getMixedAxisChartOptions.js
│ │ ├── Number
│ │ ├── Number.vue
│ │ └── NumberOptions.vue
│ │ ├── Pie
│ │ ├── Pie.vue
│ │ ├── PieOptions.vue
│ │ └── getPieChartOptions.js
│ │ ├── PivotTable
│ │ ├── PivotTable.vue
│ │ ├── PivotTableOptions.vue
│ │ └── utils.js
│ │ ├── Progress
│ │ ├── Progress.vue
│ │ └── ProgressOptions.vue
│ │ ├── Row
│ │ ├── Row.vue
│ │ ├── RowOptions.vue
│ │ └── getRowChartOptions.js
│ │ ├── Scatter
│ │ ├── Scatter.vue
│ │ ├── ScatterOptions.vue
│ │ └── getScatterChartOptions.js
│ │ ├── SeriesOption.vue
│ │ ├── Table
│ │ ├── Table.vue
│ │ ├── TableColumnOptions.vue
│ │ └── TableOptions.vue
│ │ ├── Text
│ │ ├── Text.vue
│ │ └── TextOptions.vue
│ │ ├── Trend
│ │ ├── Trend.vue
│ │ └── TrendOptions.vue
│ │ ├── useChartData.js
│ │ ├── widgetDimensions.json
│ │ └── widgets.ts
├── src2
│ ├── App.vue
│ ├── assets
│ │ ├── duckdb-logo.webp
│ │ ├── insights-logo-new-full.svg
│ │ └── insights-logo-new.svg
│ ├── auth
│ │ ├── Login.vue
│ │ ├── LoginBox.vue
│ │ └── NotFound.vue
│ ├── charts
│ │ ├── ChartBuilder.vue
│ │ ├── SharedChart.vue
│ │ ├── chart.ts
│ │ ├── colors.ts
│ │ ├── components
│ │ │ ├── BarChartConfigForm.vue
│ │ │ ├── BaseChart.vue
│ │ │ ├── ChartBuilderTable.vue
│ │ │ ├── ChartConfigForm.vue
│ │ │ ├── ChartFilterConfig.vue
│ │ │ ├── ChartIcon.vue
│ │ │ ├── ChartQuerySelector.vue
│ │ │ ├── ChartRenderer.vue
│ │ │ ├── ChartShareDialog.vue
│ │ │ ├── ChartSortConfig.vue
│ │ │ ├── ChartTitle.vue
│ │ │ ├── ChartTypeSelector.vue
│ │ │ ├── CollapsibleSection.vue
│ │ │ ├── DimensionPicker.vue
│ │ │ ├── DonutChartConfigForm.vue
│ │ │ ├── DrillDown.vue
│ │ │ ├── FunnelChartConfigForm.vue
│ │ │ ├── LineChartConfigForm.vue
│ │ │ ├── MeasurePicker.vue
│ │ │ ├── NewMeasureSelectorDialog.vue
│ │ │ ├── NumberChart.vue
│ │ │ ├── NumberChartConfigForm.vue
│ │ │ ├── Sparkline.vue
│ │ │ ├── SplitByConfig.vue
│ │ │ ├── TableChart.vue
│ │ │ ├── TableChartConfigForm.vue
│ │ │ ├── XAxisConfig.vue
│ │ │ └── YAxisConfig.vue
│ │ └── helpers.ts
│ ├── components
│ │ ├── AppSidebar.vue
│ │ ├── Autocomplete.vue
│ │ ├── Checkbox.vue
│ │ ├── Code.vue
│ │ ├── ConfirmDialog.vue
│ │ ├── ContentEditable.vue
│ │ ├── DataTable.vue
│ │ ├── DataTableColumn.vue
│ │ ├── DraggableList.vue
│ │ ├── Form.vue
│ │ ├── FormControl.vue
│ │ ├── Icons
│ │ │ ├── CSVIcon.vue
│ │ │ ├── CollapseSidebar.vue
│ │ │ ├── DuckDBIcon.vue
│ │ │ ├── FrappeCloudIcon.vue
│ │ │ ├── FrappeLogo.vue
│ │ │ ├── IndicatorIcon.vue
│ │ │ ├── JoinFullIcon.vue
│ │ │ ├── JoinInnerIcon.vue
│ │ │ ├── JoinLeftIcon.vue
│ │ │ ├── JoinRightIcon.vue
│ │ │ ├── MariaDBIcon.vue
│ │ │ ├── PostgreSQLIcon.vue
│ │ │ └── SQLiteIcon.vue
│ │ ├── InlineFormControlLabel.vue
│ │ ├── LoadingOverlay.vue
│ │ ├── Popover.vue
│ │ ├── SelectTypeDialog.vue
│ │ ├── SidebarLink.vue
│ │ ├── Switch.vue
│ │ ├── TabbedSidebarLayout.vue
│ │ ├── Toast.vue
│ │ ├── UserDropdown.vue
│ │ └── UserSelector.vue
│ ├── dashboard
│ │ ├── Dashboard.vue
│ │ ├── DashboardBuilder.vue
│ │ ├── DashboardChart.vue
│ │ ├── DashboardChartSelectorDialog.vue
│ │ ├── DashboardFilter.vue
│ │ ├── DashboardFilterEditor.vue
│ │ ├── DashboardItem.vue
│ │ ├── DashboardItemActions.vue
│ │ ├── DashboardList.vue
│ │ ├── DashboardShareDialog.vue
│ │ ├── DashboardText.vue
│ │ ├── Filter.vue
│ │ ├── SharedDashboard.vue
│ │ ├── VueGridLayout.vue
│ │ ├── dashboard.ts
│ │ └── dashboards.ts
│ ├── data_source
│ │ ├── ConnectDuckDBDialog.vue
│ │ ├── ConnectMariaDBDialog.vue
│ │ ├── ConnectPostgreSQLDialog.vue
│ │ ├── DataSourceList.vue
│ │ ├── DataSourceTable.vue
│ │ ├── DataSourceTableList.vue
│ │ ├── UploadCSVFileDialog.vue
│ │ ├── data_source.ts
│ │ ├── data_source.types.ts
│ │ └── tables.ts
│ ├── data_store
│ │ ├── DataStoreList.vue
│ │ ├── ImportTableDialog.vue
│ │ └── data_store.ts
│ ├── globals.ts
│ ├── helpers
│ │ ├── confirm_dialog.ts
│ │ ├── constants.ts
│ │ ├── dayjs.ts
│ │ ├── index.ts
│ │ ├── resource.ts
│ │ ├── store_locally.ts
│ │ └── toasts.ts
│ ├── home
│ │ ├── Home.vue
│ │ ├── HomeQuickActions.vue
│ │ └── HomeWorkbookList.vue
│ ├── index.css
│ ├── main.ts
│ ├── query
│ │ ├── Query.vue
│ │ ├── alert.ts
│ │ ├── components
│ │ │ ├── AddOperationPopover.vue
│ │ │ ├── AlertSetupDialog.vue
│ │ │ ├── ColumnFilter.vue
│ │ │ ├── ColumnFilterBody.vue
│ │ │ ├── ColumnFilterTypeDate.vue
│ │ │ ├── ColumnFilterTypeNumber.vue
│ │ │ ├── ColumnFilterTypeText.vue
│ │ │ ├── ColumnFilterValueSelector.vue
│ │ │ ├── ColumnRemove.vue
│ │ │ ├── ColumnRename.vue
│ │ │ ├── ColumnSort.vue
│ │ │ ├── ColumnTypeChange.vue
│ │ │ ├── ColumnsSelector.vue
│ │ │ ├── ColumnsSelectorDialog.vue
│ │ │ ├── CustomScriptDialog.vue
│ │ │ ├── DataTypeIcon.vue
│ │ │ ├── DatePicker.vue
│ │ │ ├── DatePickerControl.vue
│ │ │ ├── ExpressionEditor.vue
│ │ │ ├── FilterRule.vue
│ │ │ ├── FiltersSelector.vue
│ │ │ ├── FiltersSelectorDialog.vue
│ │ │ ├── InlineExpression.vue
│ │ │ ├── JoinSelectorDialog.vue
│ │ │ ├── NativeQueryEditor.vue
│ │ │ ├── NewColumnSelectorDialog.vue
│ │ │ ├── NumberFilterPicker.vue
│ │ │ ├── QueryAlertsDialog.vue
│ │ │ ├── QueryBuilder.vue
│ │ │ ├── QueryBuilderSourceSelector.vue
│ │ │ ├── QueryBuilderTable.vue
│ │ │ ├── QueryBuilderToolbar.vue
│ │ │ ├── QueryDataTable.vue
│ │ │ ├── QueryInfo.vue
│ │ │ ├── QueryOperations.vue
│ │ │ ├── RelativeDatePicker.vue
│ │ │ ├── RelativeDatePickerControl.vue
│ │ │ ├── ScriptQueryEditor.vue
│ │ │ ├── SummarySelectorDialog.vue
│ │ │ ├── UnionSelectorDialog.vue
│ │ │ ├── ViewSQLDialog.vue
│ │ │ ├── filter_utils.ts
│ │ │ ├── join_utils.ts
│ │ │ └── source_selector
│ │ │ │ ├── DataSourceSelector.vue
│ │ │ │ ├── DataSourceTableList.vue
│ │ │ │ ├── SourceSelectorDialog.vue
│ │ │ │ └── WorkbookQueryList.vue
│ │ ├── helpers.ts
│ │ └── query.ts
│ ├── router.ts
│ ├── session.ts
│ ├── settings
│ │ ├── DataStoreSettings.vue
│ │ ├── GeneralSettings.vue
│ │ ├── PermissionsSettings.vue
│ │ ├── ProfileSettings.vue
│ │ ├── SettingItem.vue
│ │ ├── Settings.vue
│ │ ├── UsersSettings.vue
│ │ └── settings.ts
│ ├── socket.ts
│ ├── styles
│ │ └── codemirror.css
│ ├── teams
│ │ ├── CreateTeamDialog.vue
│ │ ├── ManageTeamDialog.vue
│ │ ├── TeamList.vue
│ │ ├── TeamResourceSelector.vue
│ │ └── teams.ts
│ ├── telemetry.ts
│ ├── types
│ │ ├── chart.types.ts
│ │ ├── query.types.ts
│ │ └── workbook.types.ts
│ ├── users
│ │ ├── UserList.vue
│ │ └── users.ts
│ └── workbook
│ │ ├── AvatarGroup.vue
│ │ ├── Workbook.vue
│ │ ├── WorkbookChart.vue
│ │ ├── WorkbookDashboard.vue
│ │ ├── WorkbookList.vue
│ │ ├── WorkbookNavbar.vue
│ │ ├── WorkbookNavbarActions.vue
│ │ ├── WorkbookQuery.vue
│ │ ├── WorkbookQueryEmptyState.vue
│ │ ├── WorkbookShareDialog.vue
│ │ ├── WorkbookSidebar.vue
│ │ ├── WorkbookSidebarListSection.vue
│ │ ├── WorkbookTabSwitcher.vue
│ │ ├── workbook.ts
│ │ └── workbooks.ts
├── tailwind.config.js
├── tests
│ ├── dashboard_page.spec.js
│ └── query_builder.spec.js
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.js
├── insights
├── __init__.py
├── api
│ ├── __init__.py
│ ├── alerts.py
│ ├── dashboards.py
│ ├── data_sources.py
│ ├── data_store.py
│ ├── home.py
│ ├── notebooks.py
│ ├── permissions.py
│ ├── public.py
│ ├── queries.py
│ ├── setup.py
│ ├── shared.py
│ ├── subscription.py
│ ├── telemetry.py
│ ├── user.py
│ └── workbooks.py
├── cache_utils.py
├── config
│ ├── __init__.py
│ ├── desktop.py
│ └── docs.py
├── coverage.py
├── decorators.py
├── fixtures
│ ├── insights_data_source.json
│ ├── insights_data_source_v3.json
│ ├── insights_notebook.json
│ └── role.json
├── hooks.py
├── insights
│ ├── __init__.py
│ ├── doctype
│ │ ├── __init__.py
│ │ ├── insights_alert
│ │ │ ├── __init__.py
│ │ │ ├── insights_alert.js
│ │ │ ├── insights_alert.json
│ │ │ ├── insights_alert.py
│ │ │ └── test_insights_alert.py
│ │ ├── insights_chart
│ │ │ ├── __init__.py
│ │ │ ├── insights_chart.js
│ │ │ ├── insights_chart.json
│ │ │ ├── insights_chart.py
│ │ │ ├── patches
│ │ │ │ ├── __init__.py
│ │ │ │ └── convert_bar_to_row_chart.py
│ │ │ └── test_insights_chart.py
│ │ ├── insights_chart_v3
│ │ │ ├── __init__.py
│ │ │ ├── insights_chart_v3.js
│ │ │ ├── insights_chart_v3.json
│ │ │ ├── insights_chart_v3.py
│ │ │ └── test_insights_chart_v3.py
│ │ ├── insights_dashboard
│ │ │ ├── __init__.py
│ │ │ ├── insights_dashboard.js
│ │ │ ├── insights_dashboard.json
│ │ │ ├── insights_dashboard.py
│ │ │ ├── test_insights_dashboard.py
│ │ │ └── utils.py
│ │ ├── insights_dashboard_chart_v3
│ │ │ ├── __init__.py
│ │ │ ├── insights_dashboard_chart_v3.json
│ │ │ └── insights_dashboard_chart_v3.py
│ │ ├── insights_dashboard_item
│ │ │ ├── __init__.py
│ │ │ ├── insights_dashboard_item.json
│ │ │ └── insights_dashboard_item.py
│ │ ├── insights_dashboard_v3
│ │ │ ├── __init__.py
│ │ │ ├── insights_dashboard_v3.js
│ │ │ ├── insights_dashboard_v3.json
│ │ │ ├── insights_dashboard_v3.py
│ │ │ └── test_insights_dashboard_v3.py
│ │ ├── insights_data_source
│ │ │ ├── __init__.py
│ │ │ ├── insights_data_source.js
│ │ │ ├── insights_data_source.json
│ │ │ ├── insights_data_source.py
│ │ │ ├── sources
│ │ │ │ ├── base_database.py
│ │ │ │ ├── frappe_db.py
│ │ │ │ ├── mariadb.py
│ │ │ │ ├── postgresql.py
│ │ │ │ ├── query_store.py
│ │ │ │ ├── sqlite.py
│ │ │ │ └── utils.py
│ │ │ └── test_insights_data_source.py
│ │ ├── insights_data_source_v3
│ │ │ ├── __init__.py
│ │ │ ├── connectors
│ │ │ │ ├── bigquery.py
│ │ │ │ ├── duckdb.py
│ │ │ │ ├── frappe_db.py
│ │ │ │ ├── mariadb.py
│ │ │ │ ├── mssql.py
│ │ │ │ ├── postgresql.py
│ │ │ │ └── sqlite.py
│ │ │ ├── data_warehouse.py
│ │ │ ├── ibis
│ │ │ │ ├── __init__.py
│ │ │ │ ├── functions.py
│ │ │ │ └── utils.py
│ │ │ ├── ibis_utils.py
│ │ │ ├── insights_data_source_v3.js
│ │ │ ├── insights_data_source_v3.json
│ │ │ ├── insights_data_source_v3.py
│ │ │ ├── patches
│ │ │ │ ├── __init__.py
│ │ │ │ └── copy_data_sources.py
│ │ │ └── test_insights_data_source_v3.py
│ │ ├── insights_notebook
│ │ │ ├── __init__.py
│ │ │ ├── insights_notebook.js
│ │ │ ├── insights_notebook.json
│ │ │ ├── insights_notebook.py
│ │ │ └── test_insights_notebook.py
│ │ ├── insights_notebook_page
│ │ │ ├── __init__.py
│ │ │ ├── insights_notebook_page.js
│ │ │ ├── insights_notebook_page.json
│ │ │ ├── insights_notebook_page.py
│ │ │ ├── patches
│ │ │ │ ├── __init__.py
│ │ │ │ └── replace_query_builder_with_editor.py
│ │ │ └── test_insights_notebook_page.py
│ │ ├── insights_query
│ │ │ ├── __init__.py
│ │ │ ├── insights_assisted_query.py
│ │ │ ├── insights_legacy_query.py
│ │ │ ├── insights_legacy_query_utils.py
│ │ │ ├── insights_query.js
│ │ │ ├── insights_query.json
│ │ │ ├── insights_query.py
│ │ │ ├── insights_query_client.py
│ │ │ ├── insights_raw_query.py
│ │ │ ├── insights_script_query.py
│ │ │ ├── patches
│ │ │ │ ├── __init__.py
│ │ │ │ ├── flatten_columns_in_query_json.py
│ │ │ │ ├── make_query_variable_value_password_field.py
│ │ │ │ ├── migrate_old_query_to_new_query_structure.py
│ │ │ │ ├── rename_untitled_query_to_query_name.py
│ │ │ │ └── set_chart_name.py
│ │ │ ├── test_insights_query.py
│ │ │ └── utils.py
│ │ ├── insights_query_chart
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_chart.js
│ │ │ ├── insights_query_chart.json
│ │ │ ├── insights_query_chart.py
│ │ │ └── test_insights_query_chart.py
│ │ ├── insights_query_column
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_column.json
│ │ │ └── insights_query_column.py
│ │ ├── insights_query_execution_log
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_execution_log.js
│ │ │ ├── insights_query_execution_log.json
│ │ │ ├── insights_query_execution_log.py
│ │ │ └── test_insights_query_execution_log.py
│ │ ├── insights_query_result
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_result.js
│ │ │ ├── insights_query_result.json
│ │ │ ├── insights_query_result.py
│ │ │ └── test_insights_query_result.py
│ │ ├── insights_query_table
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_table.json
│ │ │ └── insights_query_table.py
│ │ ├── insights_query_transform
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_transform.js
│ │ │ ├── insights_query_transform.json
│ │ │ ├── insights_query_transform.py
│ │ │ └── test_insights_query_transform.py
│ │ ├── insights_query_v3
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_v3.js
│ │ │ ├── insights_query_v3.json
│ │ │ ├── insights_query_v3.py
│ │ │ └── test_insights_query_v3.py
│ │ ├── insights_query_variable
│ │ │ ├── __init__.py
│ │ │ ├── insights_query_variable.json
│ │ │ └── insights_query_variable.py
│ │ ├── insights_resource_permission
│ │ │ ├── __init__.py
│ │ │ ├── insights_resource_permission.json
│ │ │ └── insights_resource_permission.py
│ │ ├── insights_settings
│ │ │ ├── __init__.py
│ │ │ ├── insights_settings.js
│ │ │ ├── insights_settings.json
│ │ │ ├── insights_settings.py
│ │ │ └── test_insights_settings.py
│ │ ├── insights_table
│ │ │ ├── __init__.py
│ │ │ ├── insights_table.js
│ │ │ ├── insights_table.json
│ │ │ ├── insights_table.py
│ │ │ ├── patches
│ │ │ │ ├── __init__.py
│ │ │ │ ├── delete_duplicate_records.py
│ │ │ │ ├── delete_unused_query_based_tables.py
│ │ │ │ └── sync_table_links.py
│ │ │ ├── test_insights_table.py
│ │ │ └── test_records.json
│ │ ├── insights_table_column
│ │ │ ├── __init__.py
│ │ │ ├── insights_table_column.js
│ │ │ ├── insights_table_column.json
│ │ │ ├── insights_table_column.py
│ │ │ └── test_insights_table_column.py
│ │ ├── insights_table_import
│ │ │ ├── __init__.py
│ │ │ ├── insights_table_import.js
│ │ │ ├── insights_table_import.json
│ │ │ ├── insights_table_import.py
│ │ │ └── test_insights_table_import.py
│ │ ├── insights_table_import_log
│ │ │ ├── __init__.py
│ │ │ ├── insights_table_import_log.js
│ │ │ ├── insights_table_import_log.json
│ │ │ ├── insights_table_import_log.py
│ │ │ └── test_insights_table_import_log.py
│ │ ├── insights_table_link
│ │ │ ├── __init__.py
│ │ │ ├── insights_table_link.js
│ │ │ ├── insights_table_link.json
│ │ │ ├── insights_table_link.py
│ │ │ └── test_insights_table_link.py
│ │ ├── insights_table_link_v3
│ │ │ ├── __init__.py
│ │ │ ├── insights_table_link_v3.js
│ │ │ ├── insights_table_link_v3.json
│ │ │ ├── insights_table_link_v3.py
│ │ │ └── test_insights_table_link_v3.py
│ │ ├── insights_table_v3
│ │ │ ├── __init__.py
│ │ │ ├── insights_table_v3.js
│ │ │ ├── insights_table_v3.json
│ │ │ ├── insights_table_v3.py
│ │ │ ├── patches
│ │ │ │ └── force_sync_tables.py
│ │ │ └── test_insights_table_v3.py
│ │ ├── insights_team
│ │ │ ├── __init__.py
│ │ │ ├── insights_team.js
│ │ │ ├── insights_team.json
│ │ │ ├── insights_team.py
│ │ │ ├── insights_team_client.py
│ │ │ └── test_insights_team.py
│ │ ├── insights_team_member
│ │ │ ├── __init__.py
│ │ │ ├── insights_team_member.json
│ │ │ └── insights_team_member.py
│ │ ├── insights_user_invitation
│ │ │ ├── __init__.py
│ │ │ ├── insights_user_invitation.js
│ │ │ ├── insights_user_invitation.json
│ │ │ ├── insights_user_invitation.py
│ │ │ └── test_insights_user_invitation.py
│ │ └── insights_workbook
│ │ │ ├── __init__.py
│ │ │ ├── insights_workbook.js
│ │ │ ├── insights_workbook.json
│ │ │ ├── insights_workbook.py
│ │ │ └── test_insights_workbook.py
│ ├── page
│ │ ├── __init__.py
│ │ └── insights
│ │ │ ├── __init__.py
│ │ │ ├── insights.js
│ │ │ └── insights.json
│ └── query_builders
│ │ ├── __init__.py
│ │ ├── legacy_query_builder.py
│ │ ├── postgresql
│ │ └── builder.py
│ │ ├── sql_builder.py
│ │ ├── sql_functions.py
│ │ ├── sqlite
│ │ └── sqlite_query_builder.py
│ │ ├── test_sql_builder.py
│ │ └── utils.py
├── migrate.py
├── modules.txt
├── patches.txt
├── patches
│ ├── __init__.py
│ ├── add_column_row_to_result.py
│ ├── add_last_execution_field.py
│ ├── add_position_key_to_filter.py
│ ├── add_roles.py
│ ├── convert_duration_to_float.py
│ ├── create_query_tables.py
│ ├── enable_data_store.py
│ ├── fix_select_options_after_rename.py
│ ├── make_filter_links.py
│ ├── make_query_tables.py
│ ├── migrate_dashboard_charts.py
│ ├── modify_dashboard_layout.py
│ ├── modify_join_condition.py
│ ├── normalize_workbook.py
│ ├── refactor_dashboard_filter.py
│ ├── refactor_dashboard_item.py
│ ├── refresh_tables.py
│ ├── rename_column_type.py
│ ├── rename_count_column_name.py
│ ├── rename_data_to_config.py
│ ├── rename_doctypes.py
│ ├── rename_like_to_contains.py
│ ├── rename_target_column_field.py
│ ├── rename_visualization.py
│ ├── replace_demo_data_source.py
│ ├── replace_pivot_column_with_label.py
│ ├── reset_query_filters.py
│ ├── show_support_login_message.py
│ └── store_queries.py
├── permissions.py
├── public
│ ├── .gitkeep
│ └── js
│ │ └── setup_wizard.js
├── setup
│ ├── __init__.py
│ ├── demo.py
│ ├── insights_demo_data.duckdb
│ ├── sample_workbook.json
│ ├── setup_wizard.py
│ └── test_demo_setup.py
├── templates
│ ├── __init__.py
│ ├── alert.html
│ ├── emails
│ │ └── insights_invitation.html
│ └── pages
│ │ └── __init__.py
├── tests
│ ├── __init__.py
│ ├── test_permissions.py
│ └── utils.py
├── utils.py
└── www
│ ├── __init__.py
│ ├── insights.py
│ └── insights_v2.py
├── license.txt
├── package.json
├── pyproject.toml
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Root editor config file
2 | root = true
3 |
4 | # Common settings
5 | [*]
6 | end_of_line = lf
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 | charset = utf-8
10 |
11 | # python - standard formatting
12 | [{*.py}]
13 | indent_style = space
14 | indent_size = 4
15 |
16 | [{*.js,*.vue}]
17 | indent_style = tab
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | 9d4e122dc4b0f91c8861e61bc90015b02d793c07
2 | ac8d649974555cdf14c2aac52bc30c2b62b8aac7
3 | 3e7fd6f3b821cde5c792d2fb12fdee14fdcd1b88
4 | e8fd9e6db550f515523a6f1fc2fcf0fa9cfd8293
5 | 3faf40d64b6fa16e0efba028a19c0582e84bbe2c
6 | 1e998cd69199c090d74f4e121e52524db992c738
7 | 23228452df9591a42a2630c805cd9bfaf7224303
8 | 17e5fa7fa31df5470c8f7e8e1d49c71032452b9a
9 | fe1b4c26687d5a11b56fff60c37e9e68ebe663cb
10 | 61c4ae6cafd23e560e4bd83e07606e4f6da252fb
--------------------------------------------------------------------------------
/.github/chart-builder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/chart-builder.png
--------------------------------------------------------------------------------
/.github/helpers/install_dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo "Setting Up System Dependencies..."
5 |
6 | sudo apt update
7 | sudo apt install libcups2-dev redis-server mariadb-client-10.6
8 |
9 | install_wkhtmltopdf() {
10 | wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
11 | sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb
12 | }
13 | install_wkhtmltopdf &
14 |
--------------------------------------------------------------------------------
/.github/hero-image-v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/hero-image-v2.png
--------------------------------------------------------------------------------
/.github/hero-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/hero-image.png
--------------------------------------------------------------------------------
/.github/join-editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/join-editor.png
--------------------------------------------------------------------------------
/.github/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/logo.png
--------------------------------------------------------------------------------
/.github/new-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.github/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/preview.gif
--------------------------------------------------------------------------------
/.github/query-builder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/query-builder.png
--------------------------------------------------------------------------------
/.github/query-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/query-view.png
--------------------------------------------------------------------------------
/.github/result-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/result-view.png
--------------------------------------------------------------------------------
/.github/visualize-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/.github/visualize-view.png
--------------------------------------------------------------------------------
/.github/workflows/make-release-pr.yml:
--------------------------------------------------------------------------------
1 | # forked (:p) from frappe/frappe
2 |
3 | name: Create fortnightly release
4 | on:
5 | schedule:
6 | # 13:00 UTC -> 7pm IST on every alternate Tuesday
7 | - cron: '0 13 * * 2/2'
8 | workflow_dispatch:
9 |
10 | jobs:
11 | release:
12 | name: Release
13 | runs-on: ubuntu-latest
14 | strategy:
15 | fail-fast: false
16 |
17 | steps:
18 | - uses: octokit/request-action@v2.x
19 | with:
20 | route: POST /repos/{owner}/{repo}/pulls
21 | owner: frappe
22 | repo: insights
23 | title: |-
24 | "chore: merge 'develop' into 'main'"
25 | body: "Automated fortnightly release"
26 | base: main
27 | head: develop
28 | env:
29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Generate Semantic Release
2 | on:
3 | push:
4 | branches:
5 | - main
6 |
7 | jobs:
8 | release:
9 | name: Release
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout Entire Repository
13 | uses: actions/checkout@v3
14 | with:
15 | fetch-depth: 0
16 | persist-credentials: false
17 | - name: Setup Node.js
18 | uses: actions/setup-node@v3
19 | with:
20 | node-version: 18
21 | - name: Setup dependencies
22 | run: |
23 | npm install @semantic-release/git @semantic-release/exec --no-save
24 | - name: Create Release
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 | run: npx semantic-release
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "frappe-ui"]
2 | path = frappe-ui
3 | url = https://github.com/nextchamp-saqib/frappe-ui.git
4 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | exclude: 'node_modules|.git'
2 | default_stages: [pre-commit]
3 | fail_fast: false
4 |
5 |
6 | repos:
7 | - repo: https://github.com/pre-commit/pre-commit-hooks
8 | rev: v5.0.0
9 | hooks:
10 | - id: trailing-whitespace
11 | exclude: ".*json$|.*txt$|.*csv|.*md|.*svg"
12 | - id: check-merge-conflict
13 | - id: check-ast
14 | - id: check-json
15 | - id: check-toml
16 | - id: check-yaml
17 | - id: debug-statements
18 |
19 | - repo: https://github.com/astral-sh/ruff-pre-commit
20 | rev: v0.8.1
21 | hooks:
22 | - id: ruff
23 | name: "Run ruff import sorter"
24 | args: ["--select=I", "--fix"]
25 |
26 | - id: ruff
27 | name: "Run ruff linter"
28 |
29 | - id: ruff-format
30 | name: "Run ruff formatter"
31 |
32 | - repo: https://github.com/pre-commit/mirrors-prettier
33 | rev: v3.1.0
34 | hooks:
35 | - id: prettier
36 | types_or: [javascript, vue, scss]
37 |
38 | ci:
39 | autoupdate_schedule: weekly
40 | skip: []
41 | submodules: false
42 |
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "branches": [
3 | "main"
4 | ],
5 | "plugins": [
6 | "@semantic-release/commit-analyzer",
7 | {
8 | "preset": "angular",
9 | "releaseRules": [
10 | {
11 | "breaking": true,
12 | "release": false
13 | }
14 | ]
15 | },
16 | [
17 | "@semantic-release/exec",
18 | {
19 | "prepareCmd": 'sed -ir "s/[0-9]*\.[0-9]*\.[0-9]*/${nextRelease.version}/" insights/__init__.py'
20 | }
21 | ],
22 | [
23 | "@semantic-release/git",
24 | {
25 | "assets": [
26 | "insights/__init__.py"
27 | ],
28 | "message": "chore(release): bumped to v${nextRelease.version}"
29 | }
30 | ],
31 | "@semantic-release/github"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include MANIFEST.in
2 | include requirements.txt
3 | include *.json
4 | include *.md
5 | include *.py
6 | include *.txt
7 | recursive-include insights *.css
8 | recursive-include insights *.csv
9 | recursive-include insights *.html
10 | recursive-include insights *.ico
11 | recursive-include insights *.js
12 | recursive-include insights *.json
13 | recursive-include insights *.md
14 | recursive-include insights *.png
15 | recursive-include insights *.py
16 | recursive-include insights *.svg
17 | recursive-include insights *.txt
18 | recursive-exclude insights *.pyc
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 | services:
3 | mariadb:
4 | image: mariadb:10.8
5 | command:
6 | - --character-set-server=utf8mb4
7 | - --collation-server=utf8mb4_unicode_ci
8 | - --skip-character-set-client-handshake
9 | - --skip-innodb-read-only-compressed # Temporary fix for MariaDB 10.6
10 | environment:
11 | MYSQL_ROOT_PASSWORD: 123
12 | volumes:
13 | - mariadb-data:/var/lib/mysql
14 |
15 | redis:
16 | image: redis:alpine
17 |
18 | frappe:
19 | image: frappe/bench:latest
20 | command: bash /workspace/init.sh
21 | environment:
22 | - SHELL=/bin/bash
23 | working_dir: /home/frappe
24 | volumes:
25 | - .:/workspace
26 | ports:
27 | - 8000:8000
28 | - 9000:9000
29 |
30 | volumes:
31 | mariadb-data:
--------------------------------------------------------------------------------
/flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore =
3 | B007,
4 | B950,
5 | E101,
6 | E111,
7 | E114,
8 | E116,
9 | E117,
10 | E121,
11 | E122,
12 | E123,
13 | E124,
14 | E125,
15 | E126,
16 | E127,
17 | E128,
18 | E131,
19 | E201,
20 | E202,
21 | E203,
22 | E211,
23 | E221,
24 | E222,
25 | E223,
26 | E224,
27 | E225,
28 | E226,
29 | E228,
30 | E231,
31 | E241,
32 | E242,
33 | E251,
34 | E261,
35 | E262,
36 | E265,
37 | E266,
38 | E271,
39 | E272,
40 | E273,
41 | E274,
42 | E301,
43 | E302,
44 | E303,
45 | E305,
46 | E306,
47 | E401,
48 | E402,
49 | E501,
50 | E502,
51 | E701,
52 | E702,
53 | E703,
54 | E741,
55 | F401,
56 | F403,
57 | W191,
58 | W291,
59 | W292,
60 | W293,
61 | W391,
62 | W503,
63 | W504,
64 | E731,
65 | C420
66 |
67 | max-line-length = 88
68 |
--------------------------------------------------------------------------------
/frontend/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "browser": true,
5 | "es2021": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:vue/vue3-recommended",
10 | "plugin:prettier/recommended"
11 | ],
12 | "parser": "vue-eslint-parser",
13 | "parserOptions": {
14 | "parser": "@typescript-eslint/parser"
15 | },
16 | "plugins": [
17 | "vue",
18 | "prettier"
19 | ],
20 | "rules": {
21 | "vue/no-reserved-component-names": "off",
22 | "vue/multi-word-component-names": "off",
23 | "no-unused-vars": "off",
24 | }
25 | }
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | dist-ssr
5 | *.local
6 | /test-results/
7 | /playwright-report/
8 | /playwright/.cache/
9 |
--------------------------------------------------------------------------------
/frontend/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "useTabs": true,
5 | "printWidth": 100,
6 | "vueIndentScriptAndStyle": false
7 | }
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Frappe Insights
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/index_v2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Frappe Insights
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/frontend/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/public/favicon.png
--------------------------------------------------------------------------------
/frontend/public/insights-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/public/insights-logo.png
--------------------------------------------------------------------------------
/frontend/src/api/whitelistedMethods.ts:
--------------------------------------------------------------------------------
1 | const whitelistedMethods = {
2 | 'Insights Settings': {
3 | update_settings: 'update_settings',
4 | },
5 | 'Insights Data Source': {
6 | enqueue_sync_tables: 'enqueue_sync_tables',
7 | get_tables: 'get_tables',
8 | get_queries: 'get_queries',
9 | update_table_link: 'update_table_link',
10 | delete_table_link: 'delete_table_link',
11 | },
12 | 'Insights Table': {
13 | syncTable: 'sync_table',
14 | updateVisibility: 'update_visibility',
15 | getPreview: 'get_preview',
16 | update_column_type: 'update_column_type',
17 | },
18 | }
19 | export default function getWhitelistedMethods(doctype: string) {
20 | return whitelistedMethods[doctype as keyof typeof whitelistedMethods] || {}
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/assets/ERPNextIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/ERPNextIcon.png
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Bold.woff
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Bold.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Light.woff
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Light.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Medium.woff
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Medium.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Regular.woff
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-Regular.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-SemiBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-SemiBold.woff
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-SemiBold.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-VF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-VF.woff
--------------------------------------------------------------------------------
/frontend/src/assets/FiraCode/FiraCode-VF.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/FiraCode/FiraCode-VF.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Black.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Black.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-BlackItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-BlackItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-BlackItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-BlackItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Bold.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Bold.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-BoldItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-BoldItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraBold.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraBold.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraBoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraBoldItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraBoldItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraLight.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraLight.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraLight.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraLight.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraLightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraLightItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ExtraLightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ExtraLightItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Italic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Italic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Light.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Light.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-LightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-LightItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-LightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-LightItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Medium.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Medium.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-MediumItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-MediumItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-MediumItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-MediumItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Regular.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Regular.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-SemiBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-SemiBold.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-SemiBold.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-SemiBoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-SemiBoldItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-SemiBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-SemiBoldItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Thin.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-Thin.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ThinItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ThinItalic.woff
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-ThinItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-ThinItalic.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-italic.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-italic.var.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter-roman.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter-roman.var.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/Inter/Inter.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/Inter/Inter.var.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/MariaDBIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/MariaDBIcon.png
--------------------------------------------------------------------------------
/frontend/src/assets/PostgreSQLIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/PostgreSQLIcon.png
--------------------------------------------------------------------------------
/frontend/src/assets/SampleDataIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/SampleDataIcon.png
--------------------------------------------------------------------------------
/frontend/src/assets/SheetIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/SheetIcon.png
--------------------------------------------------------------------------------
/frontend/src/assets/add-data-source-new.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/add-data-source-new.mp4
--------------------------------------------------------------------------------
/frontend/src/assets/add-data-source.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/add-data-source.mp4
--------------------------------------------------------------------------------
/frontend/src/assets/build-first-query-new.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/build-first-query-new.mp4
--------------------------------------------------------------------------------
/frontend/src/assets/build-first-query.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/build-first-query.mp4
--------------------------------------------------------------------------------
/frontend/src/assets/create-first-dashboard-new.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/create-first-dashboard-new.mp4
--------------------------------------------------------------------------------
/frontend/src/assets/create-first-dashboard.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/assets/create-first-dashboard.mp4
--------------------------------------------------------------------------------
/frontend/src/assets/frappe-framework-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/frontend/src/assets/insights-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/frontend/src/assets/insights-logo-new.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src/components/BasePage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/frontend/src/components/Charts/ChartTitle.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | {{ title }}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src/components/Controls/LinkIcon.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
19 |
20 |
--------------------------------------------------------------------------------
/frontend/src/components/DraggableListItemMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/ExpressionHelp.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
{{ info?.description }}
8 |
9 |
10 | # Syntax
11 |
12 | {{ info?.syntax }}
13 |
14 |
15 | # Example
16 |
17 | {{ info?.example }}
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/frontend/src/components/Icons/DragHandleIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/Icons/IndicatorIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/frontend/src/components/Icons/JoinFullIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/ListFilter/FilterIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
17 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/frontend/src/components/LoginBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 | {{ props.title }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
--------------------------------------------------------------------------------
/frontend/src/components/PageTitle.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
{{ title }}
12 |
13 |
14 |
15 |
27 | {{ action.label }}
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/frontend/src/components/ResizeableInput.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
19 |
20 |
--------------------------------------------------------------------------------
/frontend/src/components/Setting.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ label }}
5 |
6 | {{ description }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
27 |
--------------------------------------------------------------------------------
/frontend/src/components/SuspenseFallback.jsx:
--------------------------------------------------------------------------------
1 | import { LoadingIndicator } from 'frappe-ui'
2 | export default {
3 | name: 'SuspenseFallback',
4 | components: { LoadingIndicator },
5 | render() {
6 | return (
7 |
8 |
9 |
10 | )
11 | },
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/components/Table/TableColumnFilter.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/frontend/src/components/Table/TableEmpty.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
9 |
10 |
No results to display
11 |
12 |
13 |
--------------------------------------------------------------------------------
/frontend/src/components/Table/TableGroupedCell.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
18 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/frontend/src/components/Table/TableLinkCell.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 | {{ label }}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/frontend/src/components/Topbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/frontend/src/dashboard/DashboardEmptyState.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | {{
10 | !dashboard.editing ? "You haven't added any charts." : 'Drag and drop charts here.'
11 | }}
12 |
13 |
18 | Add a chart
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/frontend/src/dashboard/DashboardQueryEditor.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src/dashboard/DashboardShareButton.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | Private
11 |
12 | Share
13 |
14 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/dashboard/DashboardWidgetsOptions.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
21 |
22 |
27 |
28 |
{{ widget.type }}
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/frontend/src/datasource/ConnectMariaDBDialog.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/frontend/src/datasource/ConnectPostgreDBDialog.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/frontend/src/datasource/UploadCSVFileDialog.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/frontend/src/home/Home.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | Hello, {{ session.user.first_name }} 👋
22 |
23 |
{{ today }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/frontend/src/layouts/BaseLayout.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/frontend/src/notebook/blocks/BlockAction.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | !loading && action && action()"
17 | >
18 |
19 |
20 |
25 |
26 |
27 | {{ label }}
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/frontend/src/notebook/blocks/BlockActions.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/frontend/src/notebook/blocks/chart/ChartOptionsDropdown.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 | Options
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/notebook/tiptap/extensions/Chart.js:
--------------------------------------------------------------------------------
1 | import { createNodeExtension } from './utils'
2 |
3 | import Chart from './Chart.vue'
4 | export default createNodeExtension({
5 | name: 'chart',
6 | tag: 'chart',
7 | component: Chart,
8 | attributes: {
9 | chart_name: undefined,
10 | },
11 | })
12 |
--------------------------------------------------------------------------------
/frontend/src/notebook/tiptap/extensions/Chart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/frontend/src/notebook/tiptap/extensions/Query.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/frontend/src/notebook/tiptap/extensions/QueryEditor.js:
--------------------------------------------------------------------------------
1 | import { createNodeExtension } from './utils'
2 |
3 | import Query from './Query.vue'
4 | export default createNodeExtension({
5 | name: 'query-editor',
6 | tag: 'query-editor',
7 | component: Query,
8 | attributes: {
9 | query: undefined,
10 | },
11 | })
12 |
--------------------------------------------------------------------------------
/frontend/src/notebook/tiptap/extensions/utils.js:
--------------------------------------------------------------------------------
1 | import { mergeAttributes, Node } from '@tiptap/core'
2 | import { VueNodeViewRenderer } from '@tiptap/vue-3'
3 |
4 | export function createNodeExtension(options) {
5 | const { name, component, tag, ...rest } = options
6 | return Node.create({
7 | name,
8 | group: rest.group || 'block',
9 | atom: rest.atom || true,
10 | addAttributes() {
11 | return rest.attributes || {}
12 | },
13 | parseHTML() {
14 | return [{ tag }]
15 | },
16 | renderHTML({ HTMLAttributes }) {
17 | return [tag, mergeAttributes(HTMLAttributes)]
18 | },
19 | addNodeView() {
20 | return VueNodeViewRenderer(component)
21 | },
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/frontend/src/notebook/tiptap/slash-command/commands.js:
--------------------------------------------------------------------------------
1 | import { Extension } from '@tiptap/core'
2 | import Suggestion from '@tiptap/suggestion'
3 |
4 | export default Extension.create({
5 | name: 'slash-commands',
6 |
7 | addOptions() {
8 | return {
9 | suggestion: {
10 | char: '/',
11 | command: ({ editor, range, props }) => {
12 | props.command({ editor, range })
13 | },
14 | },
15 | }
16 | },
17 |
18 | addProseMirrorPlugins() {
19 | return [
20 | Suggestion({
21 | editor: this.editor,
22 | ...this.options.suggestion,
23 | }),
24 | ]
25 | },
26 | })
27 |
--------------------------------------------------------------------------------
/frontend/src/pages/Avatars.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
21 |
--------------------------------------------------------------------------------
/frontend/src/pages/NoPermission.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
403
5 |
6 | Permission Denied
7 |
8 |
9 | You don't have permission to access this page. Make sure you have the right roles &
10 | permissions.
11 |
12 |
Go Back
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/frontend/src/pages/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
404
5 |
Not Found
6 |
The page you are looking for does not exist.
7 |
Home
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/frontend/src/pages/TrialExpired.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Your free trial has ended
7 |
8 | Hope you enjoyed it!
9 |
10 |
11 | Hello again! We hope you enjoyed your free trial of our service. You can continue
12 | using our service by upgrading to a paid plan. Click
13 |
14 | here
15 |
16 | to learn more about our pricing plans.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/query/PublicChart.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/frontend/src/query/QueryHeader.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 | Execute
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/frontend/src/query/QueryHeaderTitle.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
22 |
23 | Saving...
24 |
25 |
26 |
--------------------------------------------------------------------------------
/frontend/src/query/deprecated/Column/ColumnEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
29 |
--------------------------------------------------------------------------------
/frontend/src/query/deprecated/Filter/BinaryExpression.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ props.expression.operator }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/frontend/src/query/deprecated/Filter/CallExpression.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ props.expression.function }}
5 |
6 |
(
7 |
11 |
)
12 |
13 |
14 |
15 |
25 |
--------------------------------------------------------------------------------
/frontend/src/query/deprecated/Filter/ExpressionTerm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ value.column }}
8 |
9 |
10 |
11 | {{ value }}
12 |
13 | {{ value }}
14 |
15 |
16 |
17 |
30 |
--------------------------------------------------------------------------------
/frontend/src/query/resources/useQueryResults.js:
--------------------------------------------------------------------------------
1 | import { safeJSONParse } from '@/utils'
2 | import { createDocumentResource } from 'frappe-ui'
3 | import { computed, reactive } from 'vue'
4 | import { getFormattedResult } from '@/utils/query/results'
5 |
6 | export default function useQueryResults(result_name) {
7 | const resource = getResultResource(result_name)
8 | resource.get.fetch()
9 | return reactive({
10 | reload: () => resource.get.fetch(),
11 | loading: computed(() => resource.loading),
12 | data: computed(() => resource.doc?.results || []),
13 | columns: computed(() => resource.doc?.results?.[0] || []),
14 | formattedResults: computed(() => getFormattedResult(resource.doc?.results)),
15 | })
16 | }
17 |
18 | export function getResultResource(resultName) {
19 | return createDocumentResource({
20 | doctype: 'Insights Query Result',
21 | name: resultName,
22 | auto: false,
23 | transform: (doc) => {
24 | doc.results = safeJSONParse(doc.results, [])
25 | return doc
26 | },
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/query/visual/CumulativeSumTransformFields.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
Number Column
25 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/frontend/src/query/visual/LimitSection.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
23 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/frontend/src/query/visual/SectionHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
{{ title }}
13 |
i
14 |
15 |
16 |
{{ title }}
17 |
18 |
19 |
20 |
21 |
22 |
25 |
--------------------------------------------------------------------------------
/frontend/src/query/visual/SourceSection.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/frontend/src/query/visual/constants.js:
--------------------------------------------------------------------------------
1 | export const NEW_COLUMN = {
2 | table: '',
3 | column: '',
4 | label: '',
5 | type: '',
6 | alias: '',
7 | order: '',
8 | granularity: '',
9 | aggregation: '',
10 | format: {},
11 | expression: {},
12 | }
13 |
14 | export const NEW_FILTER = {
15 | column: { ...NEW_COLUMN },
16 | operator: {},
17 | value: {},
18 | expression: {},
19 | }
20 |
21 | export const NEW_JOIN = {
22 | join_type: { label: 'Inner Join', value: 'inner' },
23 | left_table: {},
24 | left_column: {},
25 | right_table: {},
26 | right_column: {},
27 | }
28 |
29 | export const NEW_TRANSFORM = {
30 | type: '',
31 | options: {},
32 | }
33 |
--------------------------------------------------------------------------------
/frontend/src/query/visual/messages.js:
--------------------------------------------------------------------------------
1 | export const WARN_UNABLE_TO_INFER_JOIN = (table1, table2) => ({
2 | variant: 'warning',
3 | title: 'Unable to find a relationship',
4 | message: `Please add a relationship between ${table1} and ${table2} manually`,
5 | })
6 | export const ERROR_CANNOT_ADD_SELF_AS_TABLE = () => ({
7 | variant: 'error',
8 | title: 'Cannot add self as table',
9 | message: `Please select a different table`,
10 | })
11 | export const ERROR_UNABLE_TO_RESET_MAIN_TABLE = () => ({
12 | variant: 'error',
13 | title: 'Unable to reset main table',
14 | message: 'Please remove all columns and joins before resetting the main table',
15 | })
16 |
--------------------------------------------------------------------------------
/frontend/src/socket.js:
--------------------------------------------------------------------------------
1 | import { io } from 'socket.io-client'
2 | import { socketio_port } from '../../../../sites/common_site_config.json'
3 |
4 | export function initSocket() {
5 | let host = window.location.hostname
6 | let siteName = import.meta.env.DEV ? host : window.site_name
7 | let port = window.location.port ? `:${socketio_port}` : ''
8 | let protocol = port ? 'http' : 'https'
9 | let url = `${protocol}://${host}${port}/${siteName}`
10 |
11 | let socket = io(url, {
12 | withCredentials: true,
13 | reconnectionAttempts: 5,
14 | })
15 | return socket
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/stores/cacheStore.ts:
--------------------------------------------------------------------------------
1 | import { DataSource } from '@/datasource/useDataSource'
2 | import { DataSourceTable } from '@/datasource/useDataSourceTable'
3 | import { defineStore } from 'pinia'
4 | import { ref } from 'vue'
5 |
6 | type DataSourceCache = Record
7 | type TableCache = Record
8 |
9 | const useCacheStore = defineStore('insights:cache', () => {
10 | const dataSourceCache = ref({})
11 | function getDataSource(name: string) {
12 | return dataSourceCache.value[name]
13 | }
14 | function setDataSource(name: string, dataSource: DataSource) {
15 | dataSourceCache.value[name] = dataSource
16 | }
17 |
18 | const tableCache = ref({})
19 | function getTable(name: string) {
20 | return tableCache.value[name]
21 | }
22 | function setTable(name: string, table: DataSourceTable) {
23 | tableCache.value[name] = table
24 | }
25 |
26 | return {
27 | getDataSource,
28 | setDataSource,
29 | getTable,
30 | setTable,
31 | }
32 | })
33 |
34 | export default useCacheStore
35 |
--------------------------------------------------------------------------------
/frontend/src/stores/setupStore.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src/stores/setupStore.ts
--------------------------------------------------------------------------------
/frontend/src/subscription/index.js:
--------------------------------------------------------------------------------
1 | import { createResource, call } from 'frappe-ui'
2 | import { reactive } from 'vue'
3 |
4 | const subscription = reactive({
5 | trialExpired: null,
6 | fetchTrialStatus,
7 | })
8 |
9 | async function fetchTrialStatus() {
10 | subscription.trialExpired = await call('insights.api.subscription.trial_expired')
11 | return subscription.trialExpired
12 | }
13 |
14 | export async function getLoginLink() {
15 | return await call('insights.api.subscription.get_login_link')
16 | }
17 |
18 | export async function getTrialStatus() {
19 | if (import.meta.env.DEV) return false
20 | return subscription.trialExpired !== null ? subscription.trialExpired : await fetchTrialStatus()
21 | }
22 |
23 | export default subscription
24 |
--------------------------------------------------------------------------------
/frontend/src/utils/dayjs.js:
--------------------------------------------------------------------------------
1 | import customParseFormat from 'dayjs/esm/plugin/customParseFormat'
2 | import quarterOfYear from 'dayjs/esm/plugin/quarterOfYear'
3 | import { dayjs } from 'frappe-ui'
4 |
5 | dayjs.extend(quarterOfYear)
6 | dayjs.extend(customParseFormat)
7 |
8 | export default dayjs
9 |
--------------------------------------------------------------------------------
/frontend/src/utils/prompt.js:
--------------------------------------------------------------------------------
1 | import { reactive } from 'vue'
2 |
3 | let prompt = reactive({
4 | show: false,
5 | options: {},
6 | })
7 |
8 | export default function usePrompt() {
9 | return prompt
10 | }
11 |
12 | export function showPrompt(promptOptions) {
13 | prompt.show = true
14 | prompt.options = {
15 | title: promptOptions.title,
16 | message: promptOptions.message,
17 | icon: promptOptions.icon,
18 | actions: [
19 | {
20 | ...promptOptions.primaryAction,
21 | label: promptOptions.primaryAction.label,
22 | handler: promptOptions.primaryAction.action,
23 | },
24 | {
25 | ...promptOptions.secondaryAction,
26 | label: promptOptions.secondaryAction?.label || 'Cancel',
27 | handler: promptOptions.secondaryAction?.action,
28 | },
29 | ],
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/frontend/src/utils/systemSettings.js:
--------------------------------------------------------------------------------
1 | import { createDocumentResource } from 'frappe-ui'
2 |
3 | const resource = createDocumentResource({
4 | doctype: 'System Settings',
5 | name: 'System Settings',
6 | auto: false,
7 | })
8 |
9 | export default resource
10 |
--------------------------------------------------------------------------------
/frontend/src/utils/toasts.js:
--------------------------------------------------------------------------------
1 | import Toast from '@/components/Toast.vue'
2 | import { h, markRaw } from 'vue'
3 | import { toast } from 'vue-sonner'
4 |
5 | export function createToast(toastOptions) {
6 | const options = {}
7 | if (toastOptions.message && toastOptions.title) {
8 | options.message = toastOptions.message
9 | options.title = toastOptions.title
10 | } else if (toastOptions.message && !toastOptions.title) {
11 | options.message = toastOptions.message
12 | options.title = titleCase(toastOptions.variant)
13 | } else if (!toastOptions.message && toastOptions.title) {
14 | options.message = ''
15 | options.title = toastOptions.title
16 | }
17 | const component = h(Toast, { ...toastOptions, ...options })
18 | toast.custom(markRaw(component))
19 | }
20 |
21 | function titleCase(str) {
22 | return str
23 | .toLowerCase()
24 | .split(' ')
25 | .map(function (word) {
26 | return word.charAt(0).toUpperCase() + word.slice(1)
27 | })
28 | .join(' ')
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/utils/transitions.js:
--------------------------------------------------------------------------------
1 | export const slideDownTransition = {
2 | enterActiveClass: 'transition duration-200 ease-out',
3 | leaveActiveClass: 'transition duration-150 ease-in',
4 | enterFromClass: 'translate-y-1 opacity-0',
5 | enterToClass: 'translate-y-0 opacity-100',
6 | leaveFromClass: 'translate-y-0 opacity-100',
7 | leaveToClass: 'translate-y-1 opacity-0',
8 | }
9 |
10 | export const slideRightTransition = {
11 | enterActiveClass: 'transition duration-200 ease-out',
12 | leaveActiveClass: 'transition duration-150 ease-in',
13 | enterFromClass: 'translate-x-1 opacity-0',
14 | enterToClass: 'translate-x-0 opacity-100',
15 | leaveFromClass: 'translate-x-0 opacity-100',
16 | leaveToClass: 'translate-x-1 opacity-0',
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/utils/useUsers.js:
--------------------------------------------------------------------------------
1 | import { reactive, computed } from 'vue'
2 | import { createResource } from 'frappe-ui'
3 |
4 | const userListResource = createResource('insights.api.user.get_users')
5 | const addUserResource = createResource({
6 | url: 'insights.api.user.add_insights_user',
7 | })
8 |
9 | export function useUsers() {
10 | const users = reactive({
11 | list: computed(() => userListResource.data),
12 | loading: computed(() => userListResource.loading),
13 | error: computed(() => userListResource.error),
14 | refresh: () => userListResource.fetch(),
15 | add: (user) => addUserResource.submit({ user }).then(() => userListResource.fetch()),
16 | })
17 |
18 | return users
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/src/vite-end.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Bar/Bar.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Bar/BarOptions.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Filter/Filter.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Funnel/Funnel.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/frontend/src/widgets/InvalidWidget.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 | {{ title }}
18 | {{ message }}
19 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Line/Line.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Line/LineOptions.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/frontend/src/widgets/MixedAxis/MixedAxis.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/widgets/MixedAxis/MixedAxisOptions.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Pie/Pie.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Row/RowOptions.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Scatter/Scatter.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Scatter/ScatterOptions.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Text/Text.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
40 |
--------------------------------------------------------------------------------
/frontend/src/widgets/Text/TextOptions.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 | Content
23 | (options.markdown = val)"
29 | />
30 |
31 |
32 |
--------------------------------------------------------------------------------
/frontend/src2/assets/duckdb-logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/frontend/src2/assets/duckdb-logo.webp
--------------------------------------------------------------------------------
/frontend/src2/assets/insights-logo-new.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src2/auth/LoginBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 | {{ props.title }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
--------------------------------------------------------------------------------
/frontend/src2/auth/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
404
5 |
Not Found
6 |
The page you are looking for does not exist.
7 |
Home
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/frontend/src2/charts/SharedChart.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src2/charts/colors.ts:
--------------------------------------------------------------------------------
1 |
2 | export const COLOR_MAP = {
3 | blue: '#318AD8',
4 | pink: '#F683AE',
5 | green: '#48BB74',
6 | red: '#F56B6B',
7 | yellow: '#FACF7A',
8 | purple: '#44427B',
9 | teal: '#5FD8C4',
10 | orange: '#F8814F',
11 | cyan: '#15CCEF',
12 | grey: '#A6B1B9',
13 | '#449CF0': '#449CF0',
14 | '#ECAD4B': '#ECAD4B',
15 | '#761ACB': '#761ACB',
16 | '#CB2929': '#CB2929',
17 | '#ED6396': '#ED6396',
18 | '#29CD42': '#29CD42',
19 | '#4463F0': '#4463F0',
20 | '#EC864B': '#EC864B',
21 | '#4F9DD9': '#4F9DD9',
22 | '#39E4A5': '#39E4A5',
23 | '#B4CD29': '#B4CD29',
24 | }
25 |
26 | // https://10015.io/tools/color-shades-generator
27 | export const GRADIENT_COLORS = {
28 | blue: ['#2d87d6', '#4393da', '#589fdf', '#6dace3', '#83b8e7', '#98c4eb', '#c3dcf3', '#d8e9f7', '#edf5fc', '#ffffff'],
29 | }
30 |
31 | export const getColors = () => {
32 | return Object.values(COLOR_MAP)
33 | }
34 |
35 | export const getGradientColors = (color: keyof typeof GRADIENT_COLORS) => {
36 | return GRADIENT_COLORS[color]
37 | }
38 |
--------------------------------------------------------------------------------
/frontend/src2/charts/components/ChartIcon.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/frontend/src2/charts/components/ChartTitle.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | {{ title }}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src2/charts/components/ChartTypeSelector.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
18 |
19 |
20 |
{{ item }}
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/frontend/src2/charts/components/CollapsibleSection.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 | {{ props.title }}
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/frontend/src2/components/FormControl.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src2/components/Icons/CollapseSidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/frontend/src2/components/Icons/DuckDBIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/frontend/src2/components/Icons/IndicatorIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/frontend/src2/components/Icons/JoinFullIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src2/components/InlineFormControlLabel.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
12 | {{ props.label }}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/frontend/src2/components/LoadingOverlay.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src2/dashboard/DashboardItemActions.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
34 |
35 |
--------------------------------------------------------------------------------
/frontend/src2/helpers/confirm_dialog.ts:
--------------------------------------------------------------------------------
1 | import ConfirmDialog from '../components/ConfirmDialog.vue'
2 | import { VNode, h, ref } from 'vue'
3 |
4 | export const dialogs = ref([])
5 |
6 | export function confirmDialog({
7 | title = 'Untitled',
8 | message = '',
9 | primaryActionLabel = 'Confirm',
10 | theme = 'gray',
11 | fields = [],
12 | onSuccess = () => {},
13 | }) {
14 | const component = h(ConfirmDialog, {
15 | title,
16 | message,
17 | theme,
18 | fields,
19 | onSuccess,
20 | primaryActionLabel,
21 | })
22 | dialogs.value.push(component)
23 | }
24 |
--------------------------------------------------------------------------------
/frontend/src2/helpers/dayjs.ts:
--------------------------------------------------------------------------------
1 | import customParseFormat from 'dayjs/esm/plugin/customParseFormat'
2 | import quarterOfYear from 'dayjs/esm/plugin/quarterOfYear'
3 | import { dayjs } from 'frappe-ui'
4 |
5 | dayjs.extend(quarterOfYear)
6 | dayjs.extend(customParseFormat)
7 |
8 | export default dayjs
9 |
--------------------------------------------------------------------------------
/frontend/src2/helpers/store_locally.ts:
--------------------------------------------------------------------------------
1 | import { useStorage, watchDebounced } from '@vueuse/core'
2 |
3 | type Props = {
4 | key: keyof T
5 | namespace: string
6 | serializeFn: () => T
7 | defaultValue: T
8 | }
9 | export default function storeLocally(props: Props) {
10 | const serialized = props.serializeFn()
11 | const keyValue = serialized[props.key]
12 | const localData = useStorage(`${props.namespace}:${keyValue}`, props.defaultValue)
13 | watchDebounced(props.serializeFn, (data) => (localData.value = data), {
14 | deep: true,
15 | debounce: 1000,
16 | })
17 | return localData
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src2/home/Home.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 | Hello, {{ session.user.first_name }} 👋
17 |
18 |
{{ today }}
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src2/index.css:
--------------------------------------------------------------------------------
1 | @import 'frappe-ui/src/fonts/Inter/inter.css';
2 | @import 'frappe-ui/src/style.css';
3 | @import './styles/codemirror.css';
4 |
5 | body {
6 | @apply text-base;
7 | }
8 |
9 | .tnum {
10 | font-feature-settings: 'tnum';
11 | }
12 |
13 | @layer components {
14 | /* Works on Firefox */
15 | * {
16 | scrollbar-width: thin;
17 | scrollbar-color: #c0c6cc #ebeef0;
18 | }
19 |
20 | html {
21 | scrollbar-width: auto;
22 | }
23 |
24 | /* Works on Chrome, Edge, and Safari */
25 | *::-webkit-scrollbar-thumb {
26 | background: #e2e8f0;
27 | border-radius: 6px;
28 | }
29 |
30 | *::-webkit-scrollbar-track,
31 | *::-webkit-scrollbar-corner {
32 | background: #f8fafc;
33 | }
34 |
35 | *::-webkit-scrollbar {
36 | width: 0px;
37 | height: 6px;
38 | }
39 |
40 | body::-webkit-scrollbar {
41 | width: 0px;
42 | height: 12px;
43 | }
44 | }
45 |
46 | .fade-enter-active,
47 | .fade-leave-active {
48 | transition: opacity 0.1s ease;
49 | }
50 |
51 | .fade-enter-from,
52 | .fade-leave-to {
53 | opacity: 0;
54 | }
55 |
--------------------------------------------------------------------------------
/frontend/src2/main.ts:
--------------------------------------------------------------------------------
1 | import { frappeRequest, setConfig } from 'frappe-ui'
2 | import { GridItem, GridLayout } from 'grid-layout-plus'
3 | import { createPinia } from 'pinia'
4 | import { createApp } from 'vue'
5 | import App from './App.vue'
6 | import { registerControllers, registerGlobalComponents } from './globals.ts'
7 | import './index.css'
8 | import router from './router.ts'
9 |
10 | setConfig('resourceFetcher', frappeRequest)
11 |
12 | const app = createApp(App)
13 | const pinia = createPinia()
14 |
15 | app.use(pinia)
16 | app.use(router)
17 | app.component('grid-layout', GridLayout)
18 | app.component('grid-item', GridItem)
19 |
20 | app.config.errorHandler = (err, vm, info) => {
21 | console.groupCollapsed('Unhandled Error in: ', info)
22 | console.error('Context:', vm)
23 | console.error('Error:', err)
24 | console.groupEnd()
25 | return false
26 | }
27 |
28 | registerGlobalComponents(app)
29 | registerControllers(app)
30 |
31 | app.mount('#app')
32 |
--------------------------------------------------------------------------------
/frontend/src2/query/components/ColumnRemove.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Remove
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/frontend/src2/query/components/ColumnSort.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
18 | Ascending
19 |
20 |
26 | Descending
27 |
28 |
34 | Remove Sort
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/frontend/src2/query/components/DataTypeIcon.vue:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/frontend/src2/query/components/InlineExpression.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
21 |
22 |
23 |
24 |
38 |
--------------------------------------------------------------------------------
/frontend/src2/query/components/RelativeDatePickerControl.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
23 |
24 |
25 |
26 |
27 |
28 | Done
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/frontend/src2/query/components/ViewSQLDialog.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
18 |
19 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/frontend/src2/settings/SettingItem.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 | {{ label }}
12 |
13 | {{ description }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src2/socket.ts:
--------------------------------------------------------------------------------
1 | import { io, Socket } from 'socket.io-client'
2 | import { socketio_port } from '../../../../sites/common_site_config.json'
3 |
4 | let socket: Socket
5 |
6 | export function getSocket() {
7 | if (socket) {
8 | return socket
9 | }
10 |
11 | let host = window.location.hostname
12 | let siteName = import.meta.env.DEV ? host : window.site_name
13 | let port = window.location.port ? `:${socketio_port}` : ''
14 | let protocol = port ? 'http' : 'https'
15 | let url = `${protocol}://${host}${port}/${siteName}`
16 |
17 | socket = io(url, {
18 | withCredentials: true,
19 | reconnectionAttempts: 5,
20 | })
21 | return socket
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src2/teams/CreateTeamDialog.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/frontend/src2/workbook/AvatarGroup.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src2/workbook/WorkbookChart.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
33 |
34 |
--------------------------------------------------------------------------------
/frontend/src2/workbook/WorkbookDashboard.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
30 |
31 |
--------------------------------------------------------------------------------
/frontend/src2/workbook/WorkbookQuery.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/frontend/tailwind.config.js:
--------------------------------------------------------------------------------
1 | import containerQueries from '@tailwindcss/container-queries'
2 | import frappeUIPreset from 'frappe-ui/src/tailwind/preset.js'
3 |
4 | export default {
5 | presets: [frappeUIPreset],
6 | content: [
7 | './index.html',
8 | './src/**/*.{vue,js,ts,jsx,tsx}',
9 | './src2/**/*.{vue,js,ts,jsx,tsx}',
10 | './node_modules/frappe-ui/src/components/**/*.{vue,js,ts,jsx,tsx}',
11 | '../node_modules/frappe-ui/src/components/**/*.{vue,js,ts,jsx,tsx}',
12 | ],
13 | theme: {
14 | container: {
15 | center: true,
16 | padding: {
17 | DEFAULT: '1rem',
18 | sm: '2rem',
19 | lg: '2rem',
20 | xl: '4rem',
21 | '2xl': '4rem',
22 | },
23 | },
24 | extend: {
25 | maxWidth: {
26 | 'main-content': '768px',
27 | },
28 | screens: {
29 | standalone: {
30 | raw: '(display-mode: standalone)',
31 | },
32 | },
33 | },
34 | },
35 | plugins: [containerQueries],
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/tests/dashboard_page.spec.js:
--------------------------------------------------------------------------------
1 | import { expect, test } from '@playwright/test'
2 |
3 | const login = async () => {
4 | await frappe.call('login', {
5 | usr: 'frappe@example.com',
6 | pwd: 'frappe',
7 | })
8 | }
9 |
10 | test('dashboard_page', async ({ page }) => {
11 | await page.goto('http://frappe-insights:8000/')
12 | await page.evaluate(login)
13 | await page.goto('http://frappe-insights:8000/insights')
14 | expect(page.getByText('Dashboards')).toBeTruthy()
15 | })
16 |
--------------------------------------------------------------------------------
/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": [
7 | "ES2020",
8 | "DOM",
9 | "DOM.Iterable"
10 | ],
11 | "skipLibCheck": true,
12 | /* Bundler mode */
13 | "moduleResolution": "bundler",
14 | "allowImportingTsExtensions": true,
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "noEmit": true,
18 | "jsx": "preserve",
19 | "allowJs": true,
20 | /* Linting */
21 | "strict": true,
22 | "noUnusedLocals": false,
23 | "noUnusedParameters": false,
24 | "noFallthroughCasesInSwitch": true,
25 | "paths": {
26 | "@/*": [
27 | "./src/*"
28 | ]
29 | }
30 | },
31 | "include": [
32 | "src/**/*.ts",
33 | "src/**/*.d.ts",
34 | "src/**/*.tsx",
35 | "src/**/*.vue",
36 | "src2/**/*.ts",
37 | "src2/**/*.d.ts",
38 | "src2/**/*.tsx",
39 | "src2/**/*.vue"
40 | ],
41 | "references": [
42 | {
43 | "path": "./tsconfig.node.json"
44 | }
45 | ],
46 | }
--------------------------------------------------------------------------------
/frontend/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
--------------------------------------------------------------------------------
/insights/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 |
5 | __version__ = "3.0.26"
6 |
7 |
8 | def create_toast(
9 | message: str | None = None,
10 | title: str | None = None,
11 | type: str = "info",
12 | duration: int = 5,
13 | ):
14 | import frappe
15 |
16 | if not title:
17 | title = type.capitalize()
18 |
19 | frappe.publish_realtime(
20 | event="insights_notification",
21 | user=frappe.session.user,
22 | message={
23 | "message": message,
24 | "title": title,
25 | "type": type,
26 | "user": frappe.session.user,
27 | "duration": duration,
28 | },
29 | )
30 |
31 |
32 | # for backward compatibility
33 | def notify(*args, **kwargs):
34 | create_toast(*args, **kwargs)
35 |
--------------------------------------------------------------------------------
/insights/api/alerts.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from insights.decorators import insights_whitelist, validate_type
4 |
5 |
6 | @insights_whitelist()
7 | @validate_type
8 | def get_alerts(query: str):
9 | return frappe.get_list(
10 | "Insights Alert",
11 | filters={"query": query},
12 | fields=["*"],
13 | )
14 |
--------------------------------------------------------------------------------
/insights/api/notebooks.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | @frappe.whitelist()
5 | def get_notebooks():
6 | # TODO: Add permission check
7 | return frappe.get_list(
8 | "Insights Notebook",
9 | fields=["name", "title", "creation", "modified"],
10 | order_by="creation desc",
11 | )
12 |
13 |
14 | @frappe.whitelist()
15 | def create_notebook(title):
16 | notebook = frappe.new_doc("Insights Notebook")
17 | notebook.title = title
18 | notebook.save()
19 | return notebook.name
20 |
21 |
22 | @frappe.whitelist()
23 | def create_notebook_page(notebook):
24 | notebook_page = frappe.new_doc("Insights Notebook Page")
25 | notebook_page.notebook = notebook
26 | notebook_page.title = "Untitled"
27 | notebook_page.save()
28 | return notebook_page.name
29 |
30 |
31 | @frappe.whitelist()
32 | def get_notebook_pages(notebook):
33 | return frappe.get_list(
34 | "Insights Notebook Page",
35 | filters={"notebook": notebook},
36 | fields=["name", "title", "creation", "modified"],
37 | order_by="creation desc",
38 | )
39 |
--------------------------------------------------------------------------------
/insights/cache_utils.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import hashlib
5 |
6 | import frappe
7 |
8 | EXPIRY = 60 * 10
9 |
10 |
11 | def make_digest(*args):
12 | key = ""
13 | for arg in args:
14 | if isinstance(arg, dict):
15 | key += frappe.as_json(arg)
16 | key += frappe.cstr(arg)
17 | return hashlib.md5(key.encode("utf-8")).hexdigest()
18 |
19 |
20 | def get_or_set_cache(key, func, force=False, expiry=EXPIRY):
21 | key = f"insights|{key}"
22 | cached_value = frappe.cache().get_value(key)
23 | if cached_value is not None and not force:
24 | return cached_value
25 |
26 | value = func()
27 | frappe.cache().set_value(key, value, expires_in_sec=expiry)
28 | return value
29 |
30 |
31 | @frappe.whitelist()
32 | def reset_insights_cache():
33 | frappe.only_for("System Manager")
34 | frappe.cache().delete_keys("insights*")
35 |
--------------------------------------------------------------------------------
/insights/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/config/__init__.py
--------------------------------------------------------------------------------
/insights/config/desktop.py:
--------------------------------------------------------------------------------
1 | from frappe import _
2 |
3 |
4 | def get_data():
5 | return [
6 | {
7 | "module_name": "Frappe Insights",
8 | "color": "grey",
9 | "icon": "octicon octicon-file-directory",
10 | "type": "module",
11 | "label": _("Frappe Insights"),
12 | }
13 | ]
14 |
--------------------------------------------------------------------------------
/insights/config/docs.py:
--------------------------------------------------------------------------------
1 | """
2 | Configuration for docs
3 | """
4 |
5 | # source_link = "https://github.com/[org_name]/insights"
6 | # headline = "App that does everything"
7 | # sub_heading = "Yes, you got that right the first time, everything"
8 |
9 |
10 | def get_context(context):
11 | context.brand_html = "Frappe Insights"
12 |
--------------------------------------------------------------------------------
/insights/fixtures/insights_data_source.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "doctype": "Insights Data Source",
4 | "is_site_db": 1,
5 | "name": "Site DB",
6 | "title": "Site DB",
7 | "status": "Active",
8 | "database_type": "MariaDB",
9 | "modified": "2022-01-01 00:01:00.000000",
10 | "creation": "2022-01-01 00:01:00.000000"
11 | },
12 | {
13 | "doctype": "Insights Data Source",
14 | "status": "Active",
15 | "name": "Query Store",
16 | "title": "Query Store",
17 | "database_type": "SQLite",
18 | "allow_imports": 1,
19 | "modified": "2022-01-01 00:01:00.000000",
20 | "creation": "2022-01-01 00:01:00.000000"
21 | }
22 | ]
23 |
--------------------------------------------------------------------------------
/insights/fixtures/insights_data_source_v3.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "doctype": "Insights Data Source v3",
4 | "is_site_db": 1,
5 | "is_frappe_db": 1,
6 | "name": "Site DB",
7 | "title": "Site DB",
8 | "status": "Active",
9 | "database_type": "MariaDB",
10 | "owner": "Administrator",
11 | "modified_by": "Administrator",
12 | "modified": "2022-01-01 00:01:00.000000",
13 | "creation": "2022-01-01 00:01:00.000000"
14 | }
15 | ]
16 |
--------------------------------------------------------------------------------
/insights/fixtures/insights_notebook.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Uncategorized",
4 | "owner": "Administrator",
5 | "creation": "2023-04-16 21:35:21.596615",
6 | "modified": "2023-04-16 21:35:21.596615",
7 | "modified_by": "Administrator",
8 | "docstatus": 0,
9 | "idx": 0,
10 | "title": "Uncategorized",
11 | "doctype": "Insights Notebook"
12 | }
13 | ]
14 |
--------------------------------------------------------------------------------
/insights/fixtures/role.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "bulk_actions": 0,
4 | "dashboard": 0,
5 | "desk_access": 1,
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Role",
9 | "form_sidebar": 0,
10 | "is_custom": 0,
11 | "list_sidebar": 0,
12 | "modified": "2022-12-07 21:36:44.284615",
13 | "name": "Insights Admin",
14 | "notifications": 0,
15 | "restrict_to_domain": null,
16 | "role_name": "Insights Admin",
17 | "search_bar": 0,
18 | "timeline": 0,
19 | "two_factor_auth": 0,
20 | "view_switcher": 0
21 | },
22 | {
23 | "bulk_actions": 0,
24 | "dashboard": 0,
25 | "desk_access": 0,
26 | "disabled": 0,
27 | "docstatus": 0,
28 | "doctype": "Role",
29 | "form_sidebar": 0,
30 | "is_custom": 0,
31 | "list_sidebar": 0,
32 | "modified": "2022-12-07 21:36:44.121244",
33 | "name": "Insights User",
34 | "notifications": 0,
35 | "restrict_to_domain": null,
36 | "role_name": "Insights User",
37 | "search_bar": 0,
38 | "timeline": 0,
39 | "two_factor_auth": 0,
40 | "view_switcher": 0
41 | }
42 | ]
--------------------------------------------------------------------------------
/insights/insights/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_alert/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_alert/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_alert/insights_alert.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Alert", {
5 | refresh: function (frm) {
6 | frm.add_custom_button(__("Send Alert"), function () {
7 | frappe.dom.freeze(__("Sending Alert..."));
8 | frm.call("send_alert")
9 | .then(() => {
10 | frappe.dom.unfreeze();
11 | frappe.show_alert({
12 | message: __("Alert sent"),
13 | indicator: "green",
14 | });
15 | })
16 | .catch(() => {
17 | frappe.dom.unfreeze();
18 | });
19 | });
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_alert/test_insights_alert.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsAlert(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_chart/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart/insights_chart.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Chart", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_chart/patches/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart/test_insights_chart.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsChart(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_chart_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart_v3/insights_chart_v3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Chart v3", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_chart_v3/test_insights_chart_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsChartv3(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_dashboard/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard/insights_dashboard.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('Insights Dashboard', {
5 | // refresh: function(frm) {
6 | // }
7 | })
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard/test_insights_dashboard.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsDashboard(FrappeTestCase):
9 | def test_something(self):
10 | pass
11 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_chart_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_dashboard_chart_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_chart_v3/insights_dashboard_chart_v3.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2025-03-19 14:51:15.821678",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "chart"
10 | ],
11 | "fields": [
12 | {
13 | "fieldname": "chart",
14 | "fieldtype": "Link",
15 | "label": "Chart",
16 | "options": "Insights Chart v3"
17 | }
18 | ],
19 | "index_web_pages_for_search": 1,
20 | "istable": 1,
21 | "links": [],
22 | "modified": "2025-03-19 14:51:30.724154",
23 | "modified_by": "Administrator",
24 | "module": "Insights",
25 | "name": "Insights Dashboard Chart v3",
26 | "owner": "Administrator",
27 | "permissions": [],
28 | "sort_field": "creation",
29 | "sort_order": "DESC",
30 | "states": []
31 | }
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_chart_v3/insights_dashboard_chart_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsDashboardChartv3(Document):
9 | # begin: auto-generated types
10 | # This code is auto-generated. Do not modify anything in this block.
11 |
12 | from typing import TYPE_CHECKING
13 |
14 | if TYPE_CHECKING:
15 | from frappe.types import DF
16 |
17 | chart: DF.Link | None
18 | parent: DF.Data
19 | parentfield: DF.Data
20 | parenttype: DF.Data
21 | # end: auto-generated types
22 |
23 | pass
24 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_item/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_dashboard_item/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_item/insights_dashboard_item.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsDashboardItem(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_dashboard_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_v3/insights_dashboard_v3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Dashboard v3", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_dashboard_v3/test_insights_dashboard_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsDashboardv3(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_data_source/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source/insights_data_source.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Data Source", {
5 | refresh: function (frm) {
6 | if (frm.name == "Query Store") {
7 | frm.set_read_only();
8 | }
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_data_source_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/connectors/bigquery.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | import ibis
6 |
7 |
8 | def get_bigquery_connection(data_source):
9 | project_id = data_source.bigquery_project_id
10 | dataset_id = data_source.bigquery_dataset_id
11 | credentials = data_source.bigquery_service_account_key
12 |
13 | try:
14 | from google.oauth2 import service_account
15 | except ImportError:
16 | raise ImportError("Please install google-auth to use BigQuery as a data source")
17 |
18 | credentials = service_account.Credentials.from_service_account_info(
19 | frappe.parse_json(credentials)
20 | )
21 |
22 | return ibis.bigquery.connect(
23 | project_id=project_id,
24 | dataset_id=dataset_id,
25 | credentials=credentials,
26 | )
27 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/connectors/mssql.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | import ibis
6 |
7 |
8 | def get_mssql_connection(data_source):
9 | if not frappe.conf.get("mssql_odbc_driver"):
10 | frappe.throw(
11 | "MSSQL ODBC driver path not configured. Please set it in common_site_config.json"
12 | " under 'mssql_odbc_driver' key."
13 | " Eg. 'mssql_odbc_driver': '/usr/local/lib/libtdsodbc.so' or 'FreeTDS'"
14 | )
15 |
16 | password = data_source.get_password(raise_exception=False)
17 | data_source.port = int(data_source.port or 1433)
18 |
19 | return ibis.mssql.connect(
20 | host=data_source.host,
21 | port=data_source.port,
22 | user=data_source.username,
23 | password=password,
24 | database=data_source.database_name,
25 | driver=frappe.conf.get("mssql_odbc_driver"),
26 | )
27 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/connectors/postgresql.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | from urllib.parse import quote_plus
5 |
6 | import ibis
7 |
8 |
9 | def get_postgres_connection(data_source):
10 | if data_source.connection_string:
11 | conn_string = quote_plus(data_source.connection_string)
12 | return ibis.connect(conn_string)
13 | else:
14 | password = data_source.get_password(raise_exception=False)
15 | data_source.port = int(data_source.port or 5432)
16 | return ibis.postgres.connect(
17 | host=data_source.host,
18 | port=data_source.port,
19 | user=data_source.username,
20 | password=password,
21 | database=data_source.database_name,
22 | schema=data_source.schema,
23 | sslmode="require" if data_source.use_ssl else None,
24 | )
25 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/connectors/sqlite.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import os
5 |
6 | import ibis
7 | from frappe.utils import get_files_path
8 |
9 |
10 | def get_sqlite_connection(data_source):
11 | database_path = get_files_path(is_private=1)
12 | database_path = os.path.join(database_path, f"{data_source.database_name}.sqlite")
13 | database_path = os.path.abspath(database_path)
14 | database_path = database_path.lstrip("/")
15 | return ibis.connect(database_path)
16 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/ibis/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_data_source_v3/ibis/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/insights_data_source_v3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Data Source v3", {
5 | refresh: function (frm) {},
6 | });
7 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_data_source_v3/patches/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_data_source_v3/test_insights_data_source_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsDataSourcev3(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_notebook/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook/insights_notebook.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Notebook", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook/insights_notebook.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsNotebook(Document):
9 | def on_trash(self):
10 | if self.name == "Uncategorized":
11 | frappe.throw("Cannot delete the default notebook")
12 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook/test_insights_notebook.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsNotebook(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook_page/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_notebook_page/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook_page/insights_notebook_page.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Notebook Page", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook_page/insights_notebook_page.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsNotebookPage(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook_page/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_notebook_page/patches/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook_page/patches/replace_query_builder_with_editor.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from pypika.terms import CustomFunction
3 |
4 |
5 | def execute():
6 | if not frappe.db.count("Insights Notebook Page", {"content": ["like", '%"query-builder"%']}):
7 | return
8 |
9 | pages = frappe.get_all(
10 | "Insights Notebook Page",
11 | filters={"content": ["like", '%"query-builder"%']},
12 | pluck="name",
13 | )
14 | for page in pages:
15 | content = frappe.get_value("Insights Notebook Page", page, "content")
16 | content = content.replace('"query-builder"', '"query-editor"')
17 | frappe.db.set_value(
18 | "Insights Notebook Page", page, "content", content, update_modified=False
19 | )
20 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_notebook_page/test_insights_notebook_page.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsNotebookPage(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/insights_query.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Query", {
5 | refresh(frm) {
6 | if (frm.doc.status == "Pending Execution") {
7 | frm.add_custom_button(__("Run"), () => {
8 | frm.call({
9 | method: "run",
10 | doc: frm.doc,
11 | callback: (r) => {
12 | frm.reload_doc();
13 | },
14 | });
15 | });
16 | }
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query/patches/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/patches/make_query_variable_value_password_field.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | """make_query_variable_value_password_field"""
6 |
7 | if not frappe.db.exists("DocType", "Insights Query Variable"):
8 | return
9 |
10 | query_variables = frappe.get_all(
11 | "Insights Query Variable", fields=["name", "parent", "variable_value"]
12 | )
13 | frappe.reload_doc("insights", "doctype", "insights_query")
14 | frappe.reload_doc("insights", "doctype", "insights_query_variable")
15 | for query_variable in query_variables:
16 | doc = frappe.get_doc("Insights Query", query_variable["parent"])
17 | for var in doc.variables:
18 | if var.name == query_variable["name"]:
19 | var.variable_value = query_variable["variable_value"]
20 | doc.save()
21 | break
22 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/patches/rename_untitled_query_to_query_name.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | """rename untitled query to query name"""
6 |
7 | query_names = frappe.get_all(
8 | "Insights Query",
9 | fields=["name", "title"],
10 | filters={"title": "Untitled Query"},
11 | )
12 |
13 | for query in query_names:
14 | frappe.db.set_value(
15 | "Insights Query",
16 | query.name,
17 | "title",
18 | query.name.replace("-", " ").replace("QRY", "Query"),
19 | )
20 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/patches/set_chart_name.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | # set chart name for existing insights query
6 | frappe.db.sql(
7 | """
8 | UPDATE `tabInsights Query` q
9 | SET chart = (select name from `tabInsights Chart` where query = q.name limit 1)
10 | WHERE chart IS NULL
11 | """
12 | )
13 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query/test_insights_query.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 |
5 | import frappe
6 | from frappe.tests.utils import FrappeTestCase
7 |
8 | test_dependencies = ("Insights Data Source", "Insights Table")
9 | test_records = frappe.get_test_records("Insights Query")
10 |
11 |
12 | class TestInsightsQuery(FrappeTestCase):
13 | pass
14 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_chart/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_chart/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_chart/insights_query_chart.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Query Chart", {
5 | // refresh: function(frm) {
6 | // }
7 | });
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_chart/insights_query_chart.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | from json import dumps
5 |
6 | import frappe
7 | from frappe import _dict
8 | from frappe.model.document import Document
9 |
10 |
11 | class InsightsQueryChart(Document):
12 | @frappe.whitelist()
13 | def update_doc(self, doc):
14 | doc = _dict(doc)
15 | self.title = doc.title
16 | self.type = doc.type
17 | self.config = dumps(doc.config, indent=2)
18 | self.save()
19 |
20 | @frappe.whitelist()
21 | def add_to_dashboard(self, dashboard):
22 | dashboard_doc = frappe.get_doc("Insights Dashboard", dashboard)
23 | dashboard_doc.add_item(
24 | {
25 | "item_type": "Chart",
26 | "chart": self.name,
27 | }
28 | )
29 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_chart/test_insights_query_chart.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsQueryChart(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_column/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_column/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_column/insights_query_column.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsQueryColumn(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_execution_log/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_execution_log/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_execution_log/insights_query_execution_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Query Execution Log", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_execution_log/insights_query_execution_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsQueryExecutionLog(Document):
9 | # begin: auto-generated types
10 | # This code is auto-generated. Do not modify anything in this block.
11 |
12 | from typing import TYPE_CHECKING
13 |
14 | if TYPE_CHECKING:
15 | from frappe.types import DF
16 |
17 | data_source: DF.Data | None
18 | query: DF.Data | None
19 | sql: DF.Code | None
20 | time_taken: DF.Float
21 | # end: auto-generated types
22 |
23 | pass
24 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_execution_log/test_insights_query_execution_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsQueryExecutionLog(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_result/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_result/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_result/insights_query_result.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Query Result", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_result/insights_query_result.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsQueryResult(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_result/test_insights_query_result.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsQueryResult(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_table/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_table/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_table/insights_query_table.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsQueryTable(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_transform/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_transform/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_transform/insights_query_transform.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Query Transform", {
5 | // refresh: function(frm) {
6 | // }
7 | });
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_transform/insights_query_transform.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2022-11-18 16:33:40.015647",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "type",
10 | "options"
11 | ],
12 | "fields": [
13 | {
14 | "fieldname": "type",
15 | "fieldtype": "Select",
16 | "in_list_view": 1,
17 | "label": "Type",
18 | "options": "Pivot\nUnpivot\nTranspose\nCumulativeSum"
19 | },
20 | {
21 | "default": "{}",
22 | "fieldname": "options",
23 | "fieldtype": "JSON",
24 | "in_list_view": 1,
25 | "label": "Options",
26 | "read_only": 1
27 | }
28 | ],
29 | "index_web_pages_for_search": 1,
30 | "istable": 1,
31 | "links": [],
32 | "modified": "2023-12-02 14:08:17.355102",
33 | "modified_by": "Administrator",
34 | "module": "Insights",
35 | "name": "Insights Query Transform",
36 | "owner": "Administrator",
37 | "permissions": [],
38 | "sort_field": "modified",
39 | "sort_order": "DESC",
40 | "states": []
41 | }
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_transform/insights_query_transform.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsQueryTransform(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_transform/test_insights_query_transform.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsQueryTransform(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_v3/insights_query_v3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Query v3", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_v3/test_insights_query_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsQueryv3(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_variable/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_query_variable/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_variable/insights_query_variable.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2023-08-12 23:06:17.425710",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "variable_name",
10 | "variable_value"
11 | ],
12 | "fields": [
13 | {
14 | "fieldname": "variable_name",
15 | "fieldtype": "Data",
16 | "in_list_view": 1,
17 | "label": "Variable Name",
18 | "reqd": 1
19 | },
20 | {
21 | "fieldname": "variable_value",
22 | "fieldtype": "Password",
23 | "in_list_view": 1,
24 | "label": "Variable Value",
25 | "reqd": 1
26 | }
27 | ],
28 | "index_web_pages_for_search": 1,
29 | "istable": 1,
30 | "links": [],
31 | "modified": "2023-09-18 13:27:44.064362",
32 | "modified_by": "Administrator",
33 | "module": "Insights",
34 | "name": "Insights Query Variable",
35 | "owner": "Administrator",
36 | "permissions": [],
37 | "sort_field": "modified",
38 | "sort_order": "DESC",
39 | "states": []
40 | }
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_query_variable/insights_query_variable.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsQueryVariable(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_resource_permission/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_resource_permission/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_resource_permission/insights_resource_permission.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsResourcePermission(Document):
9 | # begin: auto-generated types
10 | # This code is auto-generated. Do not modify anything in this block.
11 |
12 | from typing import TYPE_CHECKING
13 |
14 | if TYPE_CHECKING:
15 | from frappe.types import DF
16 |
17 | name: DF.Int | None
18 | parent: DF.Data
19 | parentfield: DF.Data
20 | parenttype: DF.Data
21 | resource_name: DF.DynamicLink
22 | resource_type: DF.Link
23 | table_restrictions: DF.Data | None
24 | # end: auto-generated types
25 |
26 | pass
27 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_settings/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_settings/insights_settings.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('Insights Settings', {
5 | // refresh: function(frm) {
6 | // }
7 | })
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_settings/test_insights_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsSettings(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table/insights_table.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('Insights Table', {
5 | // refresh: function(frm) {
6 | // }
7 | })
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table/patches/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table/patches/delete_unused_query_based_tables.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | """delete_unused_query_based_tables"""
6 |
7 | # get all insights tables
8 | insights_tables = frappe.get_all(
9 | "Insights Table", filters={"is_query_based": 1}, fields=["name", "table"]
10 | )
11 |
12 | # get all generate sqls
13 | generated_sqls = frappe.get_all("Insights Query", pluck="sql")
14 |
15 | # delete insights table if `table` not present in any sql
16 | for table in insights_tables:
17 | for sql in generated_sqls:
18 | if sql and table.table in sql:
19 | break
20 | else:
21 | frappe.delete_doc("Insights Table", table.name)
22 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table/test_insights_table.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 | test_dependencies = ["Insights Data Source"]
8 |
9 |
10 | class TestInsightsTable(FrappeTestCase):
11 | pass
12 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table/test_records.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "data_source": "Site DB",
4 | "table": "tabToDo",
5 | "label": "ToDo",
6 | "hidden": 0,
7 | "doctype": "Insights Table",
8 | "table_links": [],
9 | "columns": []
10 | },
11 | {
12 | "data_source": "Site DB",
13 | "table": "tabUser",
14 | "label": "User",
15 | "hidden": 0,
16 | "doctype": "Insights Table",
17 | "table_links": [],
18 | "columns": []
19 | }
20 | ]
21 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_column/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table_column/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_column/insights_table_column.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('Insights Table Column', {
5 | // refresh: function(frm) {
6 | // }
7 | })
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_column/test_insights_table_column.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsTableColumn(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_import/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table_import/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_import/insights_table_import.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Table Import", {
5 | // refresh: function(frm) {
6 | // }
7 | });
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_import/test_insights_table_import.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsTableImport(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_import_log/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table_import_log/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_import_log/insights_table_import_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Table Import Log", {
5 | refresh(frm) {
6 | if (frm.doc.status == "In Progress") {
7 | frm.add_custom_button(__("Mark as Failed"), function () {
8 | frm.call("mark_as_failed").then(() => {
9 | frm.reload_doc();
10 | });
11 | });
12 | }
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_import_log/test_insights_table_import_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsTableImportLog(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table_link/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link/insights_table_link.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('Insights Table Link', {
5 | // refresh: function(frm) {
6 | // }
7 | })
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link/insights_table_link.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsTableLink(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link/test_insights_table_link.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsTableLink(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table_link_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link_v3/insights_table_link_v3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Table Link v3", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_link_v3/test_insights_table_link_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsTableLinkv3(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_v3/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_table_v3/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_v3/insights_table_v3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Table v3", {
5 | // refresh: function(frm) {
6 | // }
7 | });
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_table_v3/test_insights_table_v3.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsTablev3(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_team/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_team/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_team/insights_team.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Insights Team", {
5 | // refresh: function(frm) {
6 | // }
7 | });
8 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_team_member/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_team_member/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_team_member/insights_team_member.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "autoname": "autoincrement",
4 | "creation": "2022-12-22 20:17:59.274364",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "user"
10 | ],
11 | "fields": [
12 | {
13 | "fieldname": "user",
14 | "fieldtype": "Link",
15 | "in_list_view": 1,
16 | "label": "User",
17 | "options": "User",
18 | "reqd": 1
19 | }
20 | ],
21 | "index_web_pages_for_search": 1,
22 | "istable": 1,
23 | "links": [],
24 | "modified": "2022-12-22 20:17:59.274364",
25 | "modified_by": "Administrator",
26 | "module": "Insights",
27 | "name": "Insights Team Member",
28 | "naming_rule": "Autoincrement",
29 | "owner": "Administrator",
30 | "permissions": [],
31 | "sort_field": "modified",
32 | "sort_order": "DESC",
33 | "states": []
34 | }
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_team_member/insights_team_member.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class InsightsTeamMember(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_user_invitation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_user_invitation/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_user_invitation/insights_user_invitation.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights User Invitation", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_user_invitation/test_insights_user_invitation.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsUserInvitation(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_workbook/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/doctype/insights_workbook/__init__.py
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_workbook/insights_workbook.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Insights Workbook", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/insights/insights/doctype/insights_workbook/test_insights_workbook.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestInsightsWorkbook(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/insights/insights/page/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/page/__init__.py
--------------------------------------------------------------------------------
/insights/insights/page/insights/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/page/insights/__init__.py
--------------------------------------------------------------------------------
/insights/insights/page/insights/insights.js:
--------------------------------------------------------------------------------
1 | frappe.pages['insights'].on_page_load = function (wrapper) {
2 | window.location.href = '/insights'
3 | }
4 |
--------------------------------------------------------------------------------
/insights/insights/page/insights/insights.json:
--------------------------------------------------------------------------------
1 | {
2 | "content": null,
3 | "creation": "2022-08-23 18:00:40.056399",
4 | "docstatus": 0,
5 | "doctype": "Page",
6 | "idx": 0,
7 | "modified": "2022-08-23 18:00:46.933155",
8 | "modified_by": "Administrator",
9 | "module": "Insights",
10 | "name": "insights",
11 | "owner": "Administrator",
12 | "page_name": "insights",
13 | "roles": [],
14 | "script": null,
15 | "standard": "Yes",
16 | "style": null,
17 | "system_page": 1,
18 | "title": "Insights"
19 | }
--------------------------------------------------------------------------------
/insights/insights/query_builders/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/insights/query_builders/__init__.py
--------------------------------------------------------------------------------
/insights/migrate.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 |
5 | import frappe
6 |
7 |
8 | def after_migrate():
9 | try:
10 | create_admin_team()
11 | except Exception:
12 | frappe.log_error(title="Error creating Admin Team")
13 |
14 |
15 | def create_admin_team():
16 | if not frappe.db.exists("Insights Team", "Admin"):
17 | frappe.get_doc(
18 | {
19 | "doctype": "Insights Team",
20 | "team_name": "Admin",
21 | "team_members": [{"user": "Administrator"}],
22 | }
23 | ).insert(ignore_permissions=True)
24 |
--------------------------------------------------------------------------------
/insights/modules.txt:
--------------------------------------------------------------------------------
1 | Insights
--------------------------------------------------------------------------------
/insights/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/patches/__init__.py
--------------------------------------------------------------------------------
/insights/patches/add_column_row_to_result.py:
--------------------------------------------------------------------------------
1 | from json import dumps
2 |
3 | import click
4 | import frappe
5 |
6 |
7 | def execute():
8 | if not frappe.db.a_row_exists("Insights Query"):
9 | return
10 |
11 | queries = frappe.get_all("Insights Query", pluck="name")
12 | for query in queries:
13 | try:
14 | doc = frappe.get_doc("Insights Query", query)
15 | results = frappe.parse_json(doc.results)
16 | if not results or "::" in str(results[0][0]):
17 | continue
18 | columns = [f"{c.label or c.column}::{c.type}" for c in doc.get_columns()]
19 | results.insert(0, columns)
20 | frappe.db.set_value(
21 | "Insights Query", query, "result", dumps(results), update_modified=False
22 | )
23 | frappe.db.commit()
24 | except Exception:
25 | frappe.db.rollback()
26 | frappe.log_error(title="Error while adding column row for - " + query)
27 | click.secho("Error while adding column row for - " + query, fg="red")
28 |
--------------------------------------------------------------------------------
/insights/patches/add_last_execution_field.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.a_row_exists("Insights Query"):
6 | return
7 |
8 | Query = frappe.qb.DocType("Insights Query")
9 | frappe.qb.update(Query).set(Query.last_execution, Query.modified).run()
10 |
--------------------------------------------------------------------------------
/insights/patches/add_position_key_to_filter.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import frappe
4 | from frappe.utils import cstr
5 |
6 |
7 | def execute():
8 | if not frappe.db.a_row_exists("Insights Query"):
9 | return
10 |
11 | queries = frappe.get_all("Insights Query", fields=["name", "filters"])
12 |
13 | for query in queries:
14 | _filters = json.loads(query.get("filters"))
15 | set_default_position(_filters)
16 | _filters = json.dumps(_filters, indent=2, default=cstr)
17 | frappe.db.set_value(
18 | "Query", query.get("name"), "filters", _filters, update_modified=False
19 | )
20 |
21 |
22 | def set_default_position(filters):
23 | if "conditions" not in filters:
24 | return
25 |
26 | filters["position"] = filters.get("position") or 1
27 | for condition in filters.get("conditions"):
28 | set_default_position(condition)
29 |
--------------------------------------------------------------------------------
/insights/patches/add_roles.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | from insights.setup import create_roles
5 |
6 |
7 | def execute():
8 | create_roles()
9 |
--------------------------------------------------------------------------------
/insights/patches/convert_duration_to_float.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.a_row_exists("Insights Query"):
6 | return
7 |
8 | Query = frappe.qb.DocType("Insights Query")
9 | frappe.qb.update(Query).set(Query.execution_time, 0).run()
10 |
--------------------------------------------------------------------------------
/insights/patches/create_query_tables.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.a_row_exists("Insights Query"):
6 | return
7 |
8 | if not frappe.db.exists("Insights Data Source", "Query Store"):
9 | frappe.get_doc(
10 | {
11 | "status": "Active",
12 | "name": "Query Store",
13 | "title": "Query Store",
14 | "database_type": "MariaDB",
15 | "doctype": "Insights Data Source",
16 | "modified": "2022-01-01 00:01:00.000000",
17 | "creation": "2022-01-01 00:01:00.000000",
18 | }
19 | ).insert()
20 |
21 | for query_name in frappe.get_all("Insights Query", pluck="name"):
22 | query = frappe.get_doc("Insights Query", query_name)
23 | query.update_query_table()
24 |
--------------------------------------------------------------------------------
/insights/patches/enable_data_store.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if frappe.db.exists("Insights Table v3", {"stored": 1}):
6 | frappe.db.set_single_value("Insights Settings", "enable_data_store", 1)
7 |
--------------------------------------------------------------------------------
/insights/patches/fix_select_options_after_rename.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 | import frappe
4 |
5 |
6 | def execute():
7 | # when the doctype Query was renamed, the options like "Permission Query" in Server Script was renamed to "Permission Insights Query"
8 | # this patch fixes the options in the docfields
9 | frappe.db.sql(
10 | "update `tabDocField` set `options` = replace(`options`, 'Insights ', '') where fieldtype = 'Select' and options like '%Insights %'"
11 | )
12 |
13 | frappe.db.sql(
14 | "update `tabCustom Field` set `options` = replace(`options`, 'Insights ', '') where fieldtype = 'Select' and options like '%Insights %'"
15 | )
16 |
17 | frappe.db.sql(
18 | "update `tabProperty Setter` set `value` = replace(`value`, 'Insights ', '') where property = 'options' and value like '%Insights %'"
19 | )
20 |
--------------------------------------------------------------------------------
/insights/patches/make_query_tables.py:
--------------------------------------------------------------------------------
1 | import click
2 | import frappe
3 |
4 |
5 | def execute():
6 | if not frappe.db.a_row_exists("Insights Query"):
7 | return
8 |
9 | for query in frappe.get_all("Insights Query", pluck="name"):
10 | try:
11 | frappe.get_doc("Insights Query", query).update_insights_table()
12 | except Exception as e:
13 | click.secho(f"Failed to create table for {query}: {e}", fg="orange")
14 |
--------------------------------------------------------------------------------
/insights/patches/migrate_dashboard_charts.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.a_row_exists("Insights Dashboard Item"):
6 | return
7 |
8 | frappe.db.sql(
9 | """
10 | UPDATE
11 | `tabInsights Dashboard Item`
12 | SET
13 | `item_type` = 'Chart',
14 | `chart` = `query_chart`
15 | WHERE
16 | `item_type` IS NULL
17 | OR `item_type` = ''
18 | """
19 | )
20 |
--------------------------------------------------------------------------------
/insights/patches/rename_column_type.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.a_row_exists("Insights Query Column"):
6 | return
7 |
8 | QueryColumn = frappe.qb.DocType("Insights Query Column")
9 | replace_map = {
10 | "Varchar": "String",
11 | "Int": "Integer",
12 | "Float": "Decimal",
13 | "Timestamp": "Datetime",
14 | "Longtext": "Text",
15 | }
16 | for old, new in replace_map.items():
17 | (
18 | frappe.qb.update(QueryColumn)
19 | .set(QueryColumn.type, new)
20 | .where(QueryColumn.type == old)
21 | .run()
22 | )
23 |
--------------------------------------------------------------------------------
/insights/patches/rename_count_column_name.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from pypika import Criterion
3 |
4 |
5 | def execute():
6 | if not frappe.db.a_row_exists("Insights Query"):
7 | return
8 |
9 | frappe.db.sql(
10 | """
11 | UPDATE
12 | `tabInsights Query Column`
13 | SET
14 | `column` = '*'
15 | WHERE
16 | `column` = '__count' OR `column` = 'count'
17 | """
18 | )
19 |
--------------------------------------------------------------------------------
/insights/patches/rename_data_to_config.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | Chart = frappe.qb.DocType("Insights Query Chart")
6 | frappe.qb.update(Chart).set(Chart.config, Chart.data).run()
7 |
--------------------------------------------------------------------------------
/insights/patches/rename_doctypes.py:
--------------------------------------------------------------------------------
1 | import click
2 | import frappe
3 |
4 |
5 | def execute():
6 | rename_map = {
7 | "Query": "Insights Query",
8 | "Table": "Insights Table",
9 | "Table Link": "Insights Table Link",
10 | "Query Visualization": "Insights Query Chart",
11 | "Data Source": "Insights Data Source",
12 | "Query Table": "Insights Query Table",
13 | "Query Column": "Insights Query Column",
14 | }
15 | for oldname, newname in rename_map.items():
16 | if frappe.db.exists("DocType", {"module": "Insights", "name": oldname}):
17 | try:
18 | frappe.rename_doc("DocType", oldname, newname, force=True)
19 | except Exception as e:
20 | frappe.log_error(title=f"Insights: Error renaming DocType {oldname}")
21 | click.echo(
22 | f"Error renaming {oldname} to {newname}: {str(e)}", color="orange"
23 | )
24 |
--------------------------------------------------------------------------------
/insights/patches/rename_like_to_contains.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.a_row_exists("Insights Query"):
6 | return
7 |
8 | queries = frappe.get_all("Insights Query", fields=["name", "filters"])
9 |
10 | for query in queries:
11 | new_filter = query.filters.replace("like", "contains")
12 | frappe.db.set_value(
13 | "Query", query.name, "filters", new_filter, update_modified=False
14 | )
15 |
--------------------------------------------------------------------------------
/insights/patches/rename_target_column_field.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 | import click
4 | import frappe
5 |
6 |
7 | def execute():
8 | for chart in frappe.get_all(
9 | "Insights Query Chart",
10 | filters={"config": ("like", "%targetColumn%")},
11 | fields=["name", "config"],
12 | ):
13 | try:
14 | chart_doc = frappe.get_doc("Insights Query Chart", chart.name)
15 | config = frappe.parse_json(chart_doc.config)
16 | config.target = config.targetColumn
17 | config.targetType = "Column"
18 | del config.targetColumn
19 | chart_doc.config = frappe.as_json(config)
20 | chart_doc.save()
21 | except Exception:
22 | click.secho(f"Failed to update {chart.name}", fg="red")
23 | frappe.log_error(title="Insights: Failed to update chart")
24 |
--------------------------------------------------------------------------------
/insights/patches/rename_visualization.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.model.utils.rename_field import rename_field
3 |
4 |
5 | def execute():
6 | try:
7 | rename_field("Insights Dashboard Item", "visualization", "query_chart")
8 | InsightsDashboardItem = frappe.qb.DocType("Insights Dashboard Item")
9 | (
10 | frappe.qb.update(InsightsDashboardItem)
11 | .set(InsightsDashboardItem.parentfield, "items")
12 | .where(InsightsDashboardItem.parentfield == "visualizations")
13 | .run()
14 | )
15 |
16 | except Exception as e:
17 | if e.args[0] != 1054:
18 | raise
19 |
--------------------------------------------------------------------------------
/insights/patches/reset_query_filters.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import frappe
4 |
5 |
6 | def execute():
7 | if not frappe.db.a_row_exists("Insights Query"):
8 | return
9 |
10 | Query = frappe.qb.DocType("Insights Query")
11 | default_filters = json.dumps(
12 | {
13 | "type": "LogicalExpression",
14 | "operator": "&&",
15 | "level": 1,
16 | "position": 1,
17 | "conditions": [],
18 | },
19 | indent=2,
20 | )
21 | frappe.qb.update(Query).set(Query.filters, default_filters).run()
22 |
--------------------------------------------------------------------------------
/insights/patches/show_support_login_message.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from insights.api.subscription import get_subscription_key
4 |
5 |
6 | def execute():
7 | if get_subscription_key():
8 | notify_users()
9 |
10 |
11 | def notify_users():
12 | # notify users about the support portal access
13 | note = frappe.new_doc("Note")
14 | note.title = "Insights Support Portal"
15 | note.public = 1
16 | note.notify_on_login = 1
17 | note.content = """
18 | Insights Support Portal You have an active subscription (or trial) for Frappe Insights. You can now access the Insights Support Portal to get help from the Frappe team.
To access the portal go to Settings -> Send Login Link
19 | """
20 | note.insert(ignore_mandatory=True)
21 |
--------------------------------------------------------------------------------
/insights/public/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/public/.gitkeep
--------------------------------------------------------------------------------
/insights/public/js/setup_wizard.js:
--------------------------------------------------------------------------------
1 | // redirect to desk page 'insights' after setup wizard is complete
2 | // 'insights' desk page redirects to '/insights'
3 | frappe.setup.welcome_page = "/app/insights";
4 |
--------------------------------------------------------------------------------
/insights/setup/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/setup/__init__.py
--------------------------------------------------------------------------------
/insights/setup/insights_demo_data.duckdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/setup/insights_demo_data.duckdb
--------------------------------------------------------------------------------
/insights/setup/test_demo_setup.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 |
5 | import unittest
6 |
7 | from .demo import DemoDataFactory
8 |
9 |
10 | class TestDemoSetup(unittest.TestCase):
11 | def test_import_demo_data(self):
12 | factory = DemoDataFactory().run()
13 | self.assertTrue(factory.demo_data_exists())
14 |
--------------------------------------------------------------------------------
/insights/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/templates/__init__.py
--------------------------------------------------------------------------------
/insights/templates/emails/insights_invitation.html:
--------------------------------------------------------------------------------
1 | You have been invited to use Insights
2 |
3 | Accept Invitation
4 |
5 |
--------------------------------------------------------------------------------
/insights/templates/pages/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/templates/pages/__init__.py
--------------------------------------------------------------------------------
/insights/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/tests/__init__.py
--------------------------------------------------------------------------------
/insights/www/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/insights/648112309292ae6a9bcddeed001623e10993f50f/insights/www/__init__.py
--------------------------------------------------------------------------------
/insights/www/insights_v2.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # GNU GPLv3 License. See license.txt
3 |
4 |
5 | import frappe
6 |
7 | from insights.api.telemetry import track_active_site
8 |
9 | no_cache = 1
10 |
11 |
12 | def get_context(context):
13 | is_v2_user = frappe.db.count("Insights Query", cache=True) > 0
14 | if not is_v2_user:
15 | frappe.local.flags.redirect_location = "/insights"
16 | raise frappe.Redirect
17 |
18 | csrf_token = frappe.sessions.get_csrf_token()
19 | frappe.db.commit()
20 | context.csrf_token = csrf_token
21 | context.site_name = frappe.local.site
22 | track_active_site()
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "type": "module",
4 | "workspaces": ["frontend", "frappe-ui"],
5 | "scripts": {
6 | "postinstall": "cd frontend && yarn install --check-files",
7 | "dev": "cd frontend && yarn dev",
8 | "build": "cd frontend && yarn build",
9 | "test": "cd frontend && yarn test"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------