diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/CacheSection.tsx b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/CacheSection.tsx index 2645a3d610cac7a8f7d42b3ab6151b89104b4193..be7ff82ee187367d1b3ab9d6f4ab98f4cb339040 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/CacheSection.tsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/CacheSection.tsx @@ -16,10 +16,7 @@ interface CacheSectionProps { onSave: (cache_ttl: number | null) => Promise<any>; } -export const CacheSection = ({ - initialCacheTTL, - onSave, -}: CacheSectionProps) => { +const CacheSection = ({ initialCacheTTL, onSave }: CacheSectionProps) => { const [cacheTTL, setCacheTTL] = useState(initialCacheTTL); const handleChange = useCallback( @@ -70,3 +67,5 @@ export const CacheSection = ({ </CacheSectionRoot> ); }; + +export default CacheSection; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/index.js b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/index.js deleted file mode 100644 index 945d4ff0f4a94ba9a3465f831687189844024d47..0000000000000000000000000000000000000000 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from "./CacheSection"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/index.ts b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2d399aae7c821bdd366a219426634dedf95f577 --- /dev/null +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheSection/index.ts @@ -0,0 +1 @@ +export { default } from "./CacheSection"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.jsx b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.jsx index 1c00d2a11c9a2b9b1b12559055ef68d988090b3c..22ea7f861b0c48877fce916b08105c6ec69a8662 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.jsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.jsx @@ -17,7 +17,7 @@ const propTypes = { message: PropTypes.string, }; -export function CacheTTLField({ field, message, ...props }) { +function CacheTTLField({ field, message, ...props }) { const hasError = !!field.error; return ( <CacheTTLFieldContainer {...props} data-testid="cache-ttl-field"> @@ -40,3 +40,5 @@ export function CacheTTLField({ field, message, ...props }) { } CacheTTLField.propTypes = propTypes; + +export default CacheTTLField; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.unit.spec.js b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.unit.spec.js index 1c2bc1a09ac54b2eefa92f67d7f9bbc338901786..206f0b1eb5492d09a347038e3a2ce86f0954e0ec 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.unit.spec.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/CacheTTLField.unit.spec.js @@ -1,7 +1,7 @@ import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { CacheTTLField } from "./CacheTTLField"; +import CacheTTLField from "./CacheTTLField"; function setup({ name = "cache_ttl", message, value }) { const onChange = jest.fn(); diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/index.js b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/index.js index 35634c0a52f23cce0c369f18f465b2e0d83d75f4..fdb4536d31ceb8129f1fd63570031137dcd82560 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/index.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/CacheTTLField/index.js @@ -1 +1 @@ -export * from "./CacheTTLField"; +export { default } from "./CacheTTLField"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/DashboardCacheSection.tsx b/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/DashboardCacheSection.tsx index 70c1606ae5b54411d4ba36f86c920d62932c153e..07db2a6f5b8e50667f9e89f862b942452a93d983 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/DashboardCacheSection.tsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/DashboardCacheSection.tsx @@ -1,15 +1,17 @@ import React from "react"; import { Dashboard } from "metabase-types/api"; -import { CacheSection } from "../CacheSection"; +import CacheSection from "../CacheSection"; interface DashboardCacheSectionProps { dashboard: Dashboard; onSave: (cache_ttl: number | null) => Promise<Dashboard>; } -export const DashboardCacheSection = ({ +const DashboardCacheSection = ({ dashboard, onSave, }: DashboardCacheSectionProps) => { return <CacheSection initialCacheTTL={dashboard.cache_ttl} onSave={onSave} />; }; + +export default DashboardCacheSection; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/index.ts b/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/index.ts index 19cf2e99322536ea8a5d1a92ffbd47552d23463a..856e7a25f65a8962c41e023ce011e207a417866d 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/index.ts +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/DashboardCacheSection/index.ts @@ -1 +1 @@ -export * from "./DashboardCacheSection"; +export { default } from "./DashboardCacheSection"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.jsx b/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.jsx index ae1574f47f4c3925c024e4bb60ba59f83fc7e005..883f1435f737c938865b6f2d30c64797eebacefb 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.jsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.jsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from "react"; import PropTypes from "prop-types"; import { t } from "ttag"; import Select, { Option } from "metabase/core/components/Select"; -import { CacheTTLField } from "../CacheTTLField"; +import CacheTTLField from "../CacheTTLField"; import { CacheFieldContainer, FieldContainer, @@ -20,7 +20,7 @@ const propTypes = { field: PropTypes.object.isRequired, }; -export function DatabaseCacheTTLField({ field }) { +function DatabaseCacheTTLField({ field }) { const [mode, setMode] = useState( field.value > 0 ? MODE.CUSTOM : MODE.INSTANCE_DEFAULT, ); @@ -55,3 +55,5 @@ export function DatabaseCacheTTLField({ field }) { } DatabaseCacheTTLField.propTypes = propTypes; + +export default DatabaseCacheTTLField; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.unit.spec.js b/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.unit.spec.js index e4670251a82814b578606c5a61490f88e9c954ef..11a4debeb19af3c9c833fb210d431b4f4f8a9b2e 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.unit.spec.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/DatabaseCacheTTLField.unit.spec.js @@ -1,7 +1,7 @@ import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { DatabaseCacheTTLField } from "./DatabaseCacheTTLField"; +import DatabaseCacheTTLField from "./DatabaseCacheTTLField"; function setup({ value = null } = {}) { const onChange = jest.fn(); diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/index.js b/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/index.js index 0e1d95230ac8c9561887e9cf1bd533b82502a442..eedffdc43ac4ffe356f2dddf31c1a3328531e83d 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/index.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/DatabaseCacheTTLField/index.js @@ -1 +1 @@ -export * from "./DatabaseCacheTTLField"; +export { default } from "./DatabaseCacheTTLField"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.styled.tsx b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.styled.tsx new file mode 100644 index 0000000000000000000000000000000000000000..33380eb47335005faa6cb9e437cc8411e490c8c3 --- /dev/null +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.styled.tsx @@ -0,0 +1,8 @@ +import styled from "@emotion/styled"; +import { color } from "metabase/lib/colors"; + +export const QueryStartLabel = styled.div` + color: ${color("text-dark")}; + font-weight: bold; + margin-bottom: 0.5rem; +`; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.tsx b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.tsx index 14651709222afbb316f7c5a0bd27707999443e46..e76a23dde785a2c1752cd21be322de3844f5df28 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.tsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.tsx @@ -1,15 +1,32 @@ import React from "react"; +import { t } from "ttag"; +import { getRelativeTime } from "metabase/lib/time"; import Question from "metabase-lib/lib/Question"; -import { CacheSection } from "../CacheSection"; +import CacheSection from "../CacheSection"; +import { QueryStartLabel } from "./QuestionCacheSection.styled"; -interface QuestionCacheSectionProps { +export interface QuestionCacheSectionProps { question: Question; onSave: (cache_ttl: number | null) => Promise<Question>; } -export const QuestionCacheSection = ({ +const QuestionCacheSection = ({ question, onSave, }: QuestionCacheSectionProps) => { - return <CacheSection initialCacheTTL={question.cacheTTL()} onSave={onSave} />; + const cacheTimestamp = question.lastQueryStart(); + const cacheRelativeTime = cacheTimestamp && getRelativeTime(cacheTimestamp); + + return ( + <div> + {cacheTimestamp && ( + <QueryStartLabel> + {t`Question last cached ${cacheRelativeTime}`} + </QueryStartLabel> + )} + <CacheSection initialCacheTTL={question.cacheTTL()} onSave={onSave} /> + </div> + ); }; + +export default QuestionCacheSection; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.unit.spec.tsx b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.unit.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e49bc029b83302aea48b5430e466b58231046256 --- /dev/null +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/QuestionCacheSection.unit.spec.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import Question from "metabase-lib/lib/Question"; +import { createMockCard } from "metabase-types/api/mocks"; +import QuestionCacheSection, { + QuestionCacheSectionProps, +} from "./QuestionCacheSection"; + +describe("QuestionCacheSection", () => { + beforeEach(() => { + jest.useFakeTimers(); + jest.setSystemTime(new Date(2020, 0, 10)); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it("should show the time of the last cached query", () => { + const props = getProps({ + question: new Question( + createMockCard({ + last_query_start: "2020-01-05T00:00:00Z", + }), + ), + }); + + render(<QuestionCacheSection {...props} />); + + const cacheLabel = screen.getByText("Question last cached 5 days ago"); + expect(cacheLabel).toBeInTheDocument(); + }); +}); + +const getProps = ( + opts?: Partial<QuestionCacheSectionProps>, +): QuestionCacheSectionProps => ({ + question: new Question(createMockCard()), + onSave: jest.fn(), + ...opts, +}); diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/index.js b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/index.js deleted file mode 100644 index 4a9bc9fc8c5ecfafa8c0b432e8dca6e4ff165b78..0000000000000000000000000000000000000000 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from "./QuestionCacheSection"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/index.ts b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..15d8fcdef47aa0bbd7182c890e64c29768cfdbf5 --- /dev/null +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheSection/index.ts @@ -0,0 +1 @@ +export { default } from "./QuestionCacheSection"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.jsx b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.jsx index 51ab91308c9270eb24ff50e4b0e4376012ffa598..65843b980eb57d34ca2e47830cfcc537aabb83ac 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.jsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.jsx @@ -31,7 +31,7 @@ function getInitialMode(question, implicitCacheTTL) { return MODE.DEFAULT; } -export function QuestionCacheTTLField({ field, question, ...props }) { +function QuestionCacheTTLField({ field, question, ...props }) { const implicitCacheTTL = useMemo( () => getQuestionsImplicitCacheTTL(question), [question], @@ -73,3 +73,5 @@ export function QuestionCacheTTLField({ field, question, ...props }) { } QuestionCacheTTLField.propTypes = propTypes; + +export default QuestionCacheTTLField; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.styled.jsx b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.styled.jsx index b10280682c6d4479988ebfcdfba83ceaecd7d653..d45fe16ef15ffaf440e3064cf53e658ff84a7825 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.styled.jsx +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.styled.jsx @@ -3,7 +3,7 @@ import { t } from "ttag"; import styled from "@emotion/styled"; import { space } from "metabase/styled-components/theme"; import Radio from "metabase/core/components/Radio"; -import { CacheTTLField } from "../CacheTTLField"; +import CacheTTLField from "../CacheTTLField"; export function CacheTTLInput(props) { return <CacheTTLField {...props} message={t`Cache results for`} />; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.unit.spec.js b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.unit.spec.js index c893c54c12890266d052998f0e21dbdc3c8c7cd3..4ef6867209dda455b0d5f74c7c36307b1681dc29 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.unit.spec.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/QuestionCacheTTLField.unit.spec.js @@ -3,7 +3,7 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { msToMinutes, msToHours } from "metabase/lib/time"; import MetabaseSettings from "metabase/lib/settings"; -import { QuestionCacheTTLField } from "./QuestionCacheTTLField"; +import QuestionCacheTTLField from "./QuestionCacheTTLField"; const TEN_MINUTES = 10 * 60 * 1000; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/index.js b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/index.js index bbc522fae5247d0b8615ebdbd2a78005e6403221..ce8a3adf3bb9ec5c81527b65d175da9c105c0171 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/index.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/components/QuestionCacheTTLField/index.js @@ -1 +1 @@ -export * from "./QuestionCacheTTLField"; +export { default } from "./QuestionCacheTTLField"; diff --git a/enterprise/frontend/src/metabase-enterprise/caching/index.js b/enterprise/frontend/src/metabase-enterprise/caching/index.js index d3b4b61fedffc84c9d27c9bd6c9727114f2923fd..a1c91a17b244bdb4a90fc74d27d740e1d267e588 100644 --- a/enterprise/frontend/src/metabase-enterprise/caching/index.js +++ b/enterprise/frontend/src/metabase-enterprise/caching/index.js @@ -3,11 +3,11 @@ import { t, jt } from "ttag"; import { hasPremiumFeature } from "metabase-enterprise/settings"; import { PLUGIN_CACHING, PLUGIN_FORM_WIDGETS } from "metabase/plugins"; import Link from "metabase/core/components/Link"; -import { CacheTTLField } from "./components/CacheTTLField"; -import { DatabaseCacheTTLField } from "./components/DatabaseCacheTTLField"; -import { QuestionCacheTTLField } from "./components/QuestionCacheTTLField"; -import { QuestionCacheSection } from "./components/QuestionCacheSection"; -import { DashboardCacheSection } from "./components/DashboardCacheSection"; +import CacheTTLField from "./components/CacheTTLField"; +import DatabaseCacheTTLField from "./components/DatabaseCacheTTLField"; +import QuestionCacheTTLField from "./components/QuestionCacheTTLField"; +import QuestionCacheSection from "./components/QuestionCacheSection"; +import DashboardCacheSection from "./components/DashboardCacheSection"; import { getQuestionsImplicitCacheTTL, diff --git a/frontend/src/metabase-lib/lib/Question.ts b/frontend/src/metabase-lib/lib/Question.ts index 6b2b0a9efd75ee7f5aae190531b0b4f46999e30f..19390191428771f672f7108eadab1667cfe72dbb 100644 --- a/frontend/src/metabase-lib/lib/Question.ts +++ b/frontend/src/metabase-lib/lib/Question.ts @@ -879,6 +879,10 @@ class QuestionInner { return this._card && this._card["last-edit-info"]; } + lastQueryStart() { + return this._card?.last_query_start; + } + isSaved(): boolean { return !!this.id(); } diff --git a/frontend/src/metabase-types/api/card.ts b/frontend/src/metabase-types/api/card.ts index 1b910ae11a2b7da9ca7841e7f27ed37129c59ca9..250d77fab289de954e12e635484db6a25fa1c6e6 100644 --- a/frontend/src/metabase-types/api/card.ts +++ b/frontend/src/metabase-types/api/card.ts @@ -1,3 +1,21 @@ +import { DatasetQuery } from "./query"; + +export interface Card extends UnsavedCard { + id: CardId; + name: string; + description: string | null; + dataset: boolean; + can_write: boolean; + cache_ttl: number | null; + last_query_start: string | null; +} + +export interface UnsavedCard { + display: string; + dataset_query: DatasetQuery; + visualization_settings: VisualizationSettings; +} + export type VisualizationSettings = { [key: string]: any; }; @@ -9,4 +27,5 @@ export interface ModerationReview { most_recent: boolean; } +export type CardId = number; export type ModerationReviewStatus = "verified"; diff --git a/frontend/src/metabase-types/api/foreignKey.ts b/frontend/src/metabase-types/api/foreign-key.ts similarity index 100% rename from frontend/src/metabase-types/api/foreignKey.ts rename to frontend/src/metabase-types/api/foreign-key.ts diff --git a/frontend/src/metabase-types/api/index.ts b/frontend/src/metabase-types/api/index.ts index 8364d41e44fba52d05eab17618708a16e699c899..32fe209bd1031033a69f8b2d31fc55e9214cc21b 100644 --- a/frontend/src/metabase-types/api/index.ts +++ b/frontend/src/metabase-types/api/index.ts @@ -5,16 +5,17 @@ export * from "./card"; export * from "./collection"; export * from "./dashboard"; export * from "./database"; -export * from "./table"; +export * from "./dataset"; export * from "./field"; -export * from "./timeline"; -export * from "./settings"; -export * from "./slack"; -export * from "./user"; +export * from "./foreign-key"; export * from "./group"; -export * from "./permissions"; -export * from "./question"; -export * from "./dataset"; export * from "./models"; export * from "./notifications"; +export * from "./permissions"; +export * from "./query"; export * from "./revision"; +export * from "./settings"; +export * from "./slack"; +export * from "./table"; +export * from "./timeline"; +export * from "./user"; diff --git a/frontend/src/metabase-types/api/mocks/card.ts b/frontend/src/metabase-types/api/mocks/card.ts index deed6e5220a491341ceb00681dc115354d20236c..41bdb3a80e3f3fd39e15e092f87f19af63033853 100644 --- a/frontend/src/metabase-types/api/mocks/card.ts +++ b/frontend/src/metabase-types/api/mocks/card.ts @@ -1,4 +1,39 @@ -import { ModerationReview } from "metabase-types/api"; +import { + ModerationReview, + Card, + UnsavedCard, + VisualizationSettings, +} from "metabase-types/api"; +import { createMockStructuredDatasetQuery } from "./query"; + +export const createMockCard = (opts?: Partial<Card>): Card => ({ + id: 1, + name: "Question", + description: null, + display: "table", + dataset_query: createMockStructuredDatasetQuery(), + visualization_settings: createMockVisualizationSettings(), + dataset: false, + can_write: false, + cache_ttl: null, + last_query_start: null, + ...opts, +}); + +export const createMockUnsavedCard = ( + opts?: Partial<UnsavedCard>, +): UnsavedCard => ({ + display: "table", + dataset_query: createMockStructuredDatasetQuery(), + visualization_settings: createMockVisualizationSettings(), + ...opts, +}); + +export const createMockVisualizationSettings = ( + opts?: Partial<VisualizationSettings>, +): VisualizationSettings => ({ + ...opts, +}); export const createMockModerationReview = ( opts?: Partial<ModerationReview>, diff --git a/frontend/src/metabase-types/api/mocks/index.ts b/frontend/src/metabase-types/api/mocks/index.ts index da5f4b52d9244b9336c39a7992b2458d4ede5019..8aabfb3f245cd5c5f6cc306ab110ae5d580dc271 100644 --- a/frontend/src/metabase-types/api/mocks/index.ts +++ b/frontend/src/metabase-types/api/mocks/index.ts @@ -6,6 +6,7 @@ export * from "./dashboard"; export * from "./database"; export * from "./dataset"; export * from "./models"; +export * from "./query"; export * from "./table"; export * from "./timeline"; export * from "./settings"; diff --git a/frontend/src/metabase-types/api/mocks/query.ts b/frontend/src/metabase-types/api/mocks/query.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ae85cf9d09ba305b4fc0169ceea0984ed685bb8 --- /dev/null +++ b/frontend/src/metabase-types/api/mocks/query.ts @@ -0,0 +1,37 @@ +import { + NativeDatasetQuery, + NativeQuery, + StructuredDatasetQuery, + StructuredQuery, +} from "metabase-types/api"; + +export const createMockStructuredQuery = ( + opts?: Partial<StructuredQuery>, +): StructuredQuery => ({ + ...opts, +}); + +export const createMockNativeQuery = ( + opts?: Partial<NativeQuery>, +): NativeQuery => ({ + query: "SELECT 1", + ...opts, +}); + +export const createMockStructuredDatasetQuery = ( + opts?: Partial<StructuredDatasetQuery>, +): StructuredDatasetQuery => ({ + type: "query", + database: 1, + query: createMockStructuredQuery(), + ...opts, +}); + +export const createMockNativeDatasetQuery = ( + opts?: Partial<NativeDatasetQuery>, +): NativeDatasetQuery => ({ + type: "native", + database: 1, + query: createMockNativeQuery(), + ...opts, +}); diff --git a/frontend/src/metabase-types/api/query.ts b/frontend/src/metabase-types/api/query.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8a490bee161390b4d7948fd6e21c020fbce0f7c --- /dev/null +++ b/frontend/src/metabase-types/api/query.ts @@ -0,0 +1,24 @@ +import { DatabaseId } from "./database"; +import { TableId } from "./table"; + +export interface StructuredQuery { + "source-table"?: TableId; +} + +export interface NativeQuery { + query: string; +} + +export interface StructuredDatasetQuery { + type: "query"; + database: DatabaseId; + query: StructuredQuery; +} + +export interface NativeDatasetQuery { + type: "native"; + database: DatabaseId; + query: NativeQuery; +} + +export type DatasetQuery = StructuredDatasetQuery | NativeDatasetQuery; diff --git a/frontend/src/metabase-types/api/question.ts b/frontend/src/metabase-types/api/question.ts deleted file mode 100644 index 464b6cddaa5616fa4b50238f575e8b06ffa7af61..0000000000000000000000000000000000000000 --- a/frontend/src/metabase-types/api/question.ts +++ /dev/null @@ -1 +0,0 @@ -export type CardId = number; diff --git a/frontend/src/metabase-types/api/table.ts b/frontend/src/metabase-types/api/table.ts index 003007194f91f56e371d20d1683733d609682eac..91e63785d68f8d3d748fb19e7a82ee0f148f04ab 100644 --- a/frontend/src/metabase-types/api/table.ts +++ b/frontend/src/metabase-types/api/table.ts @@ -1,7 +1,9 @@ -import { ForeignKey } from "../api/foreignKey"; +import { ForeignKey } from "./foreign-key"; import { Database } from "./database"; import { Field } from "./field"; +export type TableId = number | string; // can be string for virtual questions (e.g. "card__17") + export type VisibilityType = | null | "details-only" @@ -13,7 +15,7 @@ export type VisibilityType = | "cruft"; export interface Table { - id: number | string; // can be string for virtual questions (e.g. "card__17") + id: TableId; db_id: number; db?: Database; name: string; diff --git a/frontend/src/metabase-types/types/Table.ts b/frontend/src/metabase-types/types/Table.ts index 4597c4ffbbcb544bd89b9a40a75b8c2704c83231..6a63bca33791ac533bfaf8d82052c2dc8ff451d7 100644 --- a/frontend/src/metabase-types/types/Table.ts +++ b/frontend/src/metabase-types/types/Table.ts @@ -4,7 +4,7 @@ import { Field } from "./Field"; import { Segment } from "./Segment"; import { Metric } from "./Metric"; import { DatabaseId } from "./Database"; -import { ForeignKey } from "../api/foreignKey"; +import { ForeignKey } from "../api/foreign-key"; export type TableId = number; export type SchemaName = string; diff --git a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx index d68c5f60c9179006c1b61ede0abd496fd51c2674..8202d0ec56f4476ac8cf5d916af5ef6b584d96b1 100644 --- a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx +++ b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx @@ -6,7 +6,7 @@ import Question from "metabase-lib/lib/Question"; import { isPK } from "metabase/lib/schema_metadata"; import { Table } from "metabase-types/types/Table"; -import { ForeignKey } from "metabase-types/api/foreignKey"; +import { ForeignKey } from "metabase-types/api"; import { DatasetData } from "metabase-types/types/Dataset"; import { ObjectId, OnVisualizationClickType } from "./types"; diff --git a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectRelationships.tsx b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectRelationships.tsx index 1a6c20c4db71e9f554884a2842d8fd0a3216498f..3aca8c441441f2b491289fd8c4cdbeddf2b37ae9 100644 --- a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectRelationships.tsx +++ b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectRelationships.tsx @@ -3,7 +3,7 @@ import { t, jt } from "ttag"; import cx from "classnames"; import { inflect } from "inflection"; -import { ForeignKey } from "metabase-types/api/foreignKey"; +import { ForeignKey } from "metabase-types/api"; import IconBorder from "metabase/components/IconBorder"; import LoadingSpinner from "metabase/components/LoadingSpinner";