Find more data source plugins
@@ -40,3 +42,17 @@ export function DataSourceCategories({ categories, onClickDataSourceType }: Prop
>
);
}
+
+const getStyles = (theme: GrafanaTheme2) => ({
+ category: css({
+ marginBottom: theme.spacing(2),
+ }),
+ header: css({
+ fontSize: theme.typography.h5.fontSize,
+ marginBottom: theme.spacing(1),
+ }),
+ more: css({
+ margin: theme.spacing(4),
+ textAlign: 'center',
+ }),
+});
diff --git a/public/app/features/plugins/sandbox/sandbox_plugin_loader.ts b/public/app/features/plugins/sandbox/sandbox_plugin_loader.ts
index dc0b26dc2c0..c3c278cb5bf 100644
--- a/public/app/features/plugins/sandbox/sandbox_plugin_loader.ts
+++ b/public/app/features/plugins/sandbox/sandbox_plugin_loader.ts
@@ -162,7 +162,7 @@ async function doImportPluginModuleInSandbox(meta: SandboxPluginMeta): Promise
{
let classNames = cx(styles.nameCellStyle);
let name = access.name.values[p.row.index];
+ const isDeleted = access.isDeleted?.values[p.row.index];
+
if (!name?.length) {
const loading = p.row.index >= response.view.dataFrame.length;
name = loading ? 'Loading...' : 'Missing title'; // normal for panels
classNames += ' ' + styles.missingTitleText;
}
+
return (
{!response.isItemLoaded(p.row.index) ? (
+ ) : isDeleted ? (
+
{name}
) : (
{name}
@@ -136,9 +144,18 @@ export const generateColumns = (
});
availableWidth -= width;
- width = TYPE_COLUMN_WIDTH;
- columns.push(makeTypeColumn(response, access.kind, access.panel_type, width, styles));
- availableWidth -= width;
+ const showDeletedRemaining =
+ response.view.fields.permanentlyDeleteDate && hasValue(response.view.fields.permanentlyDeleteDate);
+
+ if (showDeletedRemaining && access.permanentlyDeleteDate) {
+ width = DURATION_COLUMN_WIDTH;
+ columns.push(makeDeletedRemainingColumn(response, access.permanentlyDeleteDate, width, styles));
+ availableWidth -= width;
+ } else {
+ width = TYPE_COLUMN_WIDTH;
+ columns.push(makeTypeColumn(response, access.kind, access.panel_type, width, styles));
+ availableWidth -= width;
+ }
// Show datasources if we have any
if (access.ds_uid && onDatasourceChange) {
@@ -328,6 +345,46 @@ function makeDataSourceColumn(
};
}
+function makeDeletedRemainingColumn(
+ response: QueryResponse,
+ deletedField: Field,
+ width: number,
+ styles: Record
+): TableColumn {
+ return {
+ id: 'column-delete-age',
+ field: deletedField,
+ width,
+ Header: t('search.results-table.deleted-remaining-header', 'Time remaining'),
+ Cell: (p) => {
+ const i = p.row.index;
+ const deletedDate = deletedField.values[i];
+
+ if (!deletedDate || !response.isItemLoaded(p.row.index)) {
+ return (
+
+
+
+ );
+ }
+
+ const duration = calcCoarseDuration(new Date(), deletedDate);
+ const isDeletingSoon = !Object.values(duration).some((v) => v > 0);
+ const formatted = isDeletingSoon
+ ? t('search.results-table.deleted-less-than-1-min', '< 1 min')
+ : formatDuration(duration, { style: 'long' });
+
+ return (
+
+
+ {formatted}
+
+
+ );
+ },
+ };
+}
+
function makeTypeColumn(
response: QueryResponse,
kindField: Field,
@@ -442,3 +499,22 @@ function getDisplayValue({
}
return formattedValueToString(getDisplay(value));
}
+
+/**
+ * Calculates the rough duration between two dates, keeping only the most significant unit
+ */
+function calcCoarseDuration(start: Date, end: Date) {
+ let { years = 0, months = 0, days = 0, hours = 0, minutes = 0 } = intervalToDuration({ start, end });
+
+ if (years > 0) {
+ return { years };
+ } else if (months > 0) {
+ return { months };
+ } else if (days > 0) {
+ return { days };
+ } else if (hours > 0) {
+ return { hours };
+ }
+
+ return { minutes };
+}
diff --git a/public/app/features/search/service/sql.ts b/public/app/features/search/service/sql.ts
index 15f4bff23b8..d3999434813 100644
--- a/public/app/features/search/service/sql.ts
+++ b/public/app/features/search/service/sql.ts
@@ -158,6 +158,8 @@ export class SQLSearcher implements GrafanaSearcher {
const tags: string[][] = [];
const location: string[] = [];
const sortBy: number[] = [];
+ const isDeleted: boolean[] = [];
+ const permanentlyDeleteDate: Array = [];
let sortMetaName: string | undefined;
for (let hit of rsp) {
@@ -168,6 +170,8 @@ export class SQLSearcher implements GrafanaSearcher {
url.push(hit.url);
tags.push(hit.tags);
sortBy.push(hit.sortMeta!);
+ isDeleted.push(hit.isDeleted ?? false);
+ permanentlyDeleteDate.push(hit.permanentlyDeleteDate ? new Date(hit.permanentlyDeleteDate) : undefined);
let v = hit.folderUid;
if (!v && k === 'dashboard') {
@@ -204,6 +208,8 @@ export class SQLSearcher implements GrafanaSearcher {
{ name: 'url', type: FieldType.string, config: {}, values: url },
{ name: 'tags', type: FieldType.other, config: {}, values: tags },
{ name: 'location', type: FieldType.string, config: {}, values: location },
+ { name: 'isDeleted', type: FieldType.boolean, config: {}, values: isDeleted },
+ { name: 'permanentlyDeleteDate', type: FieldType.time, config: {}, values: permanentlyDeleteDate },
],
length: name.length,
meta: {
diff --git a/public/app/features/search/service/types.ts b/public/app/features/search/service/types.ts
index 1dc3748b10d..83ceeb6758a 100644
--- a/public/app/features/search/service/types.ts
+++ b/public/app/features/search/service/types.ts
@@ -39,6 +39,8 @@ export interface DashboardQueryResult {
tags: string[];
location: string; // url that can be split
ds_uid: string[];
+ isDeleted?: boolean;
+ permanentlyDeleteDate?: Date;
// debugging fields
score: number;
diff --git a/public/app/features/search/types.ts b/public/app/features/search/types.ts
index 00f54007d8d..975e6135f12 100644
--- a/public/app/features/search/types.ts
+++ b/public/app/features/search/types.ts
@@ -30,6 +30,8 @@ export interface DashboardSearchHit extends WithAccessControlMetadata {
url: string;
sortMeta?: number;
sortMetaName?: string;
+ isDeleted?: boolean;
+ permanentlyDeleteDate?: string;
}
/**
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 66cd0278d59..9023c103880 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -1673,6 +1673,8 @@
},
"results-table": {
"datasource-header": "Data source",
+ "deleted-less-than-1-min": "< 1 min",
+ "deleted-remaining-header": "Time remaining",
"location-header": "Location",
"name-header": "Name",
"tags-header": "Tags",
diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json
index ce0e02527a6..5da2cc41ad0 100644
--- a/public/locales/pseudo-LOCALE/grafana.json
+++ b/public/locales/pseudo-LOCALE/grafana.json
@@ -1673,6 +1673,8 @@
},
"results-table": {
"datasource-header": "Đäŧä şőūřčę",
+ "deleted-less-than-1-min": "< 1 mįʼn",
+ "deleted-remaining-header": "Ŧįmę řęmäįʼnįʼnģ",
"location-header": "Ŀőčäŧįőʼn",
"name-header": "Ńämę",
"tags-header": "Ŧäģş",
diff --git a/public/sass/_angular.scss b/public/sass/_angular.scss
index 7745ac688b3..69fe9fdf8db 100644
--- a/public/sass/_angular.scss
+++ b/public/sass/_angular.scss
@@ -1864,3 +1864,74 @@ $easing: cubic-bezier(0, 0, 0.265, 1);
background: transparent;
display: block;
}
+
+.add-data-source-item {
+ padding: $space-md;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ background: $card-background;
+ border-radius: 3px;
+ margin-bottom: $space-xxs;
+
+ &:hover {
+ background: $card-background-hover;
+
+ .add-data-source-item-actions {
+ opacity: 1;
+ transition: 0.15s opacity ease-in-out;
+ }
+ }
+}
+
+.add-data-source-item-text-wrapper {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+}
+
+.add-data-source-item-logo {
+ margin-right: $space-lg;
+ margin-left: $space-sm;
+ width: 55px;
+ max-height: 55px;
+}
+
+.add-data-source-item-desc {
+ font-size: $font-size-sm;
+ color: $text-color-weak;
+}
+
+.add-data-source-item-actions {
+ opacity: 0;
+ padding-left: $space-md;
+ display: flex;
+ align-items: center;
+
+ > button {
+ margin-left: $space-md;
+ cursor: pointer;
+ }
+}
+
+.add-data-source-item-badge {
+ margin-top: 6px;
+}
+
+.add-data-source-item-text {
+ font-size: $font-size-h5;
+}
+
+.panel-empty {
+ display: flex;
+ align-items: center;
+ height: 100%;
+ width: 100%;
+
+ p {
+ text-align: center;
+ color: $text-muted;
+ font-size: $font-size-lg;
+ width: 100%;
+ }
+}
diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss
index fa9ec6aec8b..b24b2d4648e 100644
--- a/public/sass/_grafana.scss
+++ b/public/sass/_grafana.scss
@@ -24,15 +24,12 @@
@import 'components/tags';
@import 'components/gf-form';
@import 'components/filter-table';
-@import 'components/slate_editor';
@import 'components/modals';
@import 'components/dropdown';
@import 'components/infobox';
@import 'components/query_editor';
@import 'components/query_part';
@import 'components/dashboard_grid';
-@import 'components/add_data_source';
-@import 'components/panel_header';
// PAGES
@import 'pages/dashboard';
diff --git a/public/sass/components/_add_data_source.scss b/public/sass/components/_add_data_source.scss
deleted file mode 100644
index c641948c285..00000000000
--- a/public/sass/components/_add_data_source.scss
+++ /dev/null
@@ -1,86 +0,0 @@
-.add-data-source-header {
- margin-bottom: $space-xl;
- padding-top: $spacer;
- text-align: center;
-}
-
-.add-data-source-search {
- display: flex;
- justify-content: center;
- margin-bottom: $space-lg;
-}
-
-.add-data-source-category {
- margin-bottom: $space-md;
-}
-
-.add-data-source-category__header {
- font-size: $font-size-h5;
- margin-bottom: $space-sm;
-}
-
-.add-data-source-item {
- padding: $space-md;
- display: flex;
- align-items: center;
- cursor: pointer;
- background: $card-background;
- border-radius: 3px;
- margin-bottom: $space-xxs;
-
- &:hover {
- background: $card-background-hover;
-
- .add-data-source-item-actions {
- opacity: 1;
- transition: 0.15s opacity ease-in-out;
- }
- }
-}
-
-.add-data-source-item-text-wrapper {
- display: flex;
- flex-direction: column;
- flex-grow: 1;
-}
-
-.add-data-source-item-desc {
- font-size: $font-size-sm;
- color: $text-color-weak;
-}
-
-.add-data-source-item-badge {
- margin-top: 6px;
-}
-
-.add-data-source-item-text {
- font-size: $font-size-h5;
-}
-
-.add-data-source-item-logo {
- margin-right: $space-lg;
- margin-left: $space-sm;
- width: 55px;
- max-height: 55px;
-}
-
-.add-data-source-item-actions {
- opacity: 0;
- padding-left: $space-md;
- display: flex;
- align-items: center;
-
- > button {
- margin-left: $space-md;
- cursor: pointer;
- }
-}
-
-.add-datasource-item-actions__btn-icon {
- margin-left: $space-sm;
-}
-
-.add-data-source-more {
- text-align: center;
- margin: $space-xl;
-}
diff --git a/public/sass/components/_panel_header.scss b/public/sass/components/_panel_header.scss
deleted file mode 100644
index 15db9a5d91f..00000000000
--- a/public/sass/components/_panel_header.scss
+++ /dev/null
@@ -1,122 +0,0 @@
-.panel-header {
- &:hover {
- transition: background-color 0.1s ease-in-out;
- background-color: $panel-header-hover-bg;
- }
-}
-
-.panel-container--no-title {
- .panel-header {
- position: absolute;
- left: min(50px, 10%); // allows space for interaction in the corders
- right: min(50px, 10%);
- z-index: $panel-header-z-index;
-
- &:hover {
- left: 0;
- right: 0;
- }
- }
- .panel-content {
- height: 100%;
- }
-}
-
-.panel-title-container {
- cursor: move;
- word-wrap: break-word;
- display: block;
-}
-
-.panel-title {
- border: 0px;
- font-weight: $font-weight-semi-bold;
- position: relative;
- width: 100%;
- display: flex;
- flex-wrap: nowrap;
- justify-content: center;
- height: $panel-header-height;
- line-height: $panel-header-height;
- align-items: center;
-}
-
-.panel-menu-container {
- width: 0px;
- height: 19px;
- display: inline-block;
-}
-
-.panel-menu-toggle {
- position: absolute;
- top: calc(50% - 9px);
- color: $text-color-weak;
- cursor: pointer;
- margin: 2px 0 0 2px;
- visibility: hidden;
- opacity: 0;
-
- &:hover {
- color: $link-hover-color;
- }
-}
-
-.panel-loading {
- position: absolute;
- top: 0px;
- right: 4px;
- z-index: $panel-header-z-index + 1;
- font-size: $font-size-lg;
- color: $text-color-weak;
-
- &:hover {
- cursor: pointer;
- }
-}
-
-.panel-empty {
- display: flex;
- align-items: center;
- height: 100%;
- width: 100%;
-
- p {
- text-align: center;
- color: $text-muted;
- font-size: $font-size-lg;
- width: 100%;
- }
-}
-
-.panel-menu {
- top: 25px;
- left: -100px;
-}
-
-.panel-info-content {
- overflow: auto;
-
- code {
- white-space: normal;
- word-wrap: break-word;
- }
-
- pre > code {
- display: block;
- }
-
- .panel-info-corner-links {
- list-style: none;
- padding-left: 0;
- }
-}
-
-.panel-time-info {
- font-weight: $font-weight-semi-bold;
- float: right;
- margin-right: 8px;
- color: $blue;
- font-size: 85%;
- position: absolute;
- right: 0;
-}
diff --git a/public/sass/components/_slate_editor.scss b/public/sass/components/_slate_editor.scss
deleted file mode 100644
index bd596c4542a..00000000000
--- a/public/sass/components/_slate_editor.scss
+++ /dev/null
@@ -1,165 +0,0 @@
-.slate-query-field {
- font-size: $font-size-base;
- font-family: $font-family-monospace;
- height: auto;
- word-break: break-word;
- // Affects only placeholder in query field. Adds scrollbar only if content is cropped.
- overflow: auto;
-}
-
-.slate-query-field__wrapper {
- position: relative;
- display: inline-block;
- padding: 6px 8px;
- min-height: $input-height;
- width: 100%;
- color: $text-color;
- background-color: $input-bg;
- background-image: none;
- border: $input-border;
- border-radius: $border-radius;
- transition: all 0.3s;
- line-height: $input-line-height;
-}
-
-.slate-query-field__wrapper--disabled {
- background-color: inherit;
- cursor: not-allowed;
-}
-
-.slate-typeahead {
- .typeahead {
- position: relative;
- z-index: $zindex-typeahead;
- border-radius: $border-radius;
- border: $panel-border;
- max-height: calc(66vh);
- overflow-y: scroll;
- overflow-x: hidden;
- outline: none;
- list-style: none;
- background: $panel-bg;
- color: $text-color;
- box-shadow: $typeahead-shadow;
- }
-
- .typeahead-group__title {
- color: $text-color-weak;
- font-size: $font-size-sm;
- line-height: $line-height-base;
- padding: $space-sm;
- }
-
- .typeahead-item {
- height: auto;
- font-family: $font-family-monospace;
- padding: $space-sm $space-sm $space-sm $space-md;
- font-size: $font-size-sm;
- text-overflow: ellipsis;
- overflow: hidden;
- z-index: 1;
- display: block;
- white-space: nowrap;
- cursor: pointer;
- transition:
- color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
- border-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
- background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
- padding 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
- }
-
- .typeahead-item__selected {
- background-color: $typeahead-selected-bg;
-
- .typeahead-item-hint {
- font-size: $font-size-xs;
- color: $text-color;
- white-space: normal;
- }
- }
-
- .typeahead-match {
- color: $typeahead-selected-color;
- border-bottom: 1px solid $typeahead-selected-color;
- // Undoing mark styling
- padding: inherit;
- background: inherit;
- }
-}
-
-/* SYNTAX */
-
-.slate-query-field,
-.prism-syntax-highlight {
- .token.comment,
- .token.block-comment,
- .token.prolog,
- .token.doctype,
- .token.cdata {
- color: $text-color-weak;
- }
-
- .token.variable,
- .token.entity {
- color: $text-color;
- }
-
- .token.property,
- .token.tag,
- .token.constant,
- .token.symbol,
- .token.deleted {
- color: $query-red;
- }
-
- .token.attr-value,
- .token.selector,
- .token.string,
- .token.char,
- .token.builtin,
- .token.inserted {
- color: $query-green;
- }
-
- .token.boolean,
- .token.number,
- .token.operator,
- .token.url {
- color: $query-purple;
- }
-
- .token.function,
- .token.attr-name,
- .token.function-name,
- .token.atrule,
- .token.keyword,
- .token.class-name {
- color: $text-blue;
- }
-
- .token.punctuation,
- .token.regex,
- .token.important {
- color: $query-orange;
- }
-
- .token.important {
- font-weight: normal;
- }
-
- .token.bold {
- font-weight: bold;
- }
-
- .token.italic {
- font-style: italic;
- }
-
- .token.entity {
- cursor: help;
- }
-
- .namespace {
- opacity: 0.7;
- }
-}
diff --git a/yarn.lock b/yarn.lock
index 705fe14a62a..a61ec50de55 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8000,13 +8000,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/add@npm:^2":
- version: 2.0.3
- resolution: "@types/add@npm:2.0.3"
- checksum: 10/c15815ef0e4903113f7fda84b4c2704a1b694fd6f53a6e3c9327b5b7067aba676c75e696b950401de45be7646b37b7059303a7bb5c4363de3eb3e0c06d25f565
- languageName: node
- linkType: hard
-
"@types/angular-route@npm:1.7.6":
version: 1.7.6
resolution: "@types/angular-route@npm:1.7.6"
@@ -17148,7 +17141,6 @@ __metadata:
"@testing-library/react": "npm:15.0.2"
"@testing-library/react-hooks": "npm:^8.0.1"
"@testing-library/user-event": "npm:14.5.2"
- "@types/add": "npm:^2"
"@types/angular": "npm:1.8.9"
"@types/angular-route": "npm:1.7.6"
"@types/babel__core": "npm:^7"
@@ -17408,7 +17400,6 @@ __metadata:
xlsx: "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz"
yaml: "npm:^2.0.0"
yargs: "npm:^17.5.1"
- yarn: "npm:^1.22.22"
dependenciesMeta:
prettier@3.3.1:
unplugged: true
@@ -31158,16 +31149,6 @@ __metadata:
languageName: node
linkType: hard
-"yarn@npm:^1.22.22":
- version: 1.22.22
- resolution: "yarn@npm:1.22.22"
- bin:
- yarn: bin/yarn.js
- yarnpkg: bin/yarn.js
- checksum: 10/98d80230beaa81f186b2256dff5ef9dce2dd6073c94299209f8e562da9018cff4275c95c27c788aaa4a9c3c186ea8a9aee9a5b83570696a4c8a9d1fff2d4da3a
- languageName: node
- linkType: hard
-
"yauzl@npm:^2.10.0":
version: 2.10.0
resolution: "yauzl@npm:2.10.0"