@malloy-publisher/sdk 0.0.196-dev → 0.0.198-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +77 -77
  2. package/TREE_SHAKING.md +11 -11
  3. package/dist/{ServerProvider-CvZTC0sJ.es.js → ServerProvider-DDScRRDc.es.js} +1393 -1393
  4. package/dist/ServerProvider-IhQ4aYBm.cjs.js +1 -0
  5. package/dist/client/api.d.ts +674 -674
  6. package/dist/client/configuration.d.ts +1 -1
  7. package/dist/client/index.cjs.js +1 -1
  8. package/dist/client/index.d.ts +1 -1
  9. package/dist/client/index.es.js +53 -53
  10. package/dist/components/Environment/Environment.d.ts +6 -0
  11. package/dist/components/Environment/index.d.ts +2 -0
  12. package/dist/components/Home/AddEnvironmentDialog.d.ts +1 -0
  13. package/dist/components/Home/DeleteEnvironmentDialog.d.ts +5 -0
  14. package/dist/components/Home/EditEnvironmentDialog.d.ts +7 -0
  15. package/dist/components/Home/Home.d.ts +2 -2
  16. package/dist/components/ServerProvider.d.ts +4 -4
  17. package/dist/components/index.d.ts +1 -1
  18. package/dist/{core-mP4paWtU.cjs.js → core-7-3Jcsb0.cjs.js} +1 -1
  19. package/dist/{core-BrfQApxh.es.js → core-w79IMXAG.es.js} +1 -1
  20. package/dist/hooks/useDimensionFiltersFromSpec.d.ts +3 -3
  21. package/dist/hooks/useDimensionFiltersQuery.d.ts +3 -3
  22. package/dist/hooks/useDimensionalFilterRangeData.d.ts +4 -4
  23. package/dist/{index-ClRkROAM.es.js → index-CN0_kZSF.es.js} +13067 -13033
  24. package/dist/{index-CW09s4Xx.cjs.js → index-Xo_ADux9.cjs.js} +34 -34
  25. package/dist/index.cjs.js +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.es.js +21 -21
  28. package/dist/utils/formatting.d.ts +1 -1
  29. package/dist/utils/parsing.d.ts +2 -2
  30. package/package.json +1 -1
  31. package/src/components/Connections/DeleteConnectionDialog.tsx +1 -0
  32. package/src/components/Connections/EditConnectionDialog.tsx +2 -0
  33. package/src/components/{Project → Environment}/About.tsx +8 -4
  34. package/src/components/{Project → Environment}/AddPackageDialog.tsx +5 -3
  35. package/src/components/{Project → Environment}/ConnectionExplorer.tsx +14 -14
  36. package/src/components/{Project → Environment}/DeletePackageDialog.tsx +2 -2
  37. package/src/components/{Project → Environment}/EditPackageDialog.tsx +18 -13
  38. package/src/components/{Project/Project.tsx → Environment/Environment.tsx} +6 -6
  39. package/src/components/{Project → Environment}/Packages.tsx +6 -5
  40. package/src/components/Environment/index.ts +2 -0
  41. package/src/components/Home/{AddProjectDialog.tsx → AddEnvironmentDialog.tsx} +21 -18
  42. package/src/components/Home/{DeleteProjectDialog.tsx → DeleteEnvironmentDialog.tsx} +14 -13
  43. package/src/components/Home/{EditProjectDialog.tsx → EditEnvironmentDialog.tsx} +32 -28
  44. package/src/components/Home/Home.tsx +39 -38
  45. package/src/components/Model/ModelCell.tsx +2 -2
  46. package/src/components/Model/SourcesExplorer.tsx +2 -2
  47. package/src/components/Model/useModelData.ts +3 -3
  48. package/src/components/Notebook/Notebook.tsx +7 -7
  49. package/src/components/Package/Config.tsx +4 -4
  50. package/src/components/Package/Connections.tsx +15 -15
  51. package/src/components/Package/Databases.tsx +4 -4
  52. package/src/components/Package/Models.tsx +4 -4
  53. package/src/components/Package/Notebooks.tsx +4 -4
  54. package/src/components/QueryResult/QueryResult.tsx +6 -6
  55. package/src/components/ServerProvider.tsx +5 -5
  56. package/src/components/Workbook/ModelPicker.tsx +4 -4
  57. package/src/components/Workbook/Workbook.tsx +4 -4
  58. package/src/components/index.ts +1 -1
  59. package/src/hooks/useDimensionFiltersFromSpec.ts +5 -5
  60. package/src/hooks/useDimensionFiltersQuery.ts +6 -6
  61. package/src/hooks/useDimensionalFilterRangeData.ts +7 -7
  62. package/src/hooks/useRawQueryData.ts +3 -3
  63. package/src/index.ts +1 -1
  64. package/src/utils/formatting.spec.ts +22 -21
  65. package/src/utils/formatting.ts +8 -7
  66. package/src/utils/parsing.spec.ts +23 -19
  67. package/src/utils/parsing.ts +8 -6
  68. package/dist/ServerProvider-BMsmCksc.cjs.js +0 -1
  69. package/dist/components/Home/AddProjectDialog.d.ts +0 -1
  70. package/dist/components/Home/DeleteProjectDialog.d.ts +0 -5
  71. package/dist/components/Home/EditProjectDialog.d.ts +0 -7
  72. package/dist/components/Project/Project.d.ts +0 -6
  73. package/dist/components/Project/index.d.ts +0 -2
  74. package/src/components/Project/index.ts +0 -2
  75. /package/dist/components/{Project → Environment}/About.d.ts +0 -0
  76. /package/dist/components/{Project → Environment}/AddPackageDialog.d.ts +0 -0
  77. /package/dist/components/{Project → Environment}/ConnectionExplorer.d.ts +0 -0
  78. /package/dist/components/{Project → Environment}/DeletePackageDialog.d.ts +0 -0
  79. /package/dist/components/{Project → Environment}/EditPackageDialog.d.ts +0 -0
  80. /package/dist/components/{Project → Environment}/Packages.d.ts +0 -0
@@ -16,12 +16,12 @@ interface QueryResultProps {
16
16
 
17
17
  export function createEmbeddedQueryResult(props: QueryResultProps): string {
18
18
  const {
19
- projectName: optionalProjectName,
19
+ environmentName: optionalProjectName,
20
20
  packageName: optionalPackageName,
21
21
  } = parseResourceUri(props.resourceUri);
22
22
  if (!optionalProjectName || !optionalPackageName) {
23
23
  throw new Error(
24
- "Project and Package name must be provided for query embedding.",
24
+ "Environment and Package name must be provided for query embedding.",
25
25
  );
26
26
  }
27
27
  return JSON.stringify({
@@ -66,11 +66,11 @@ export default function QueryResult({
66
66
  resourceUri,
67
67
  height = 400,
68
68
  }: QueryResultProps) {
69
- const { modelPath, projectName, packageName, versionId } =
69
+ const { modelPath, environmentName, packageName, versionId } =
70
70
  parseResourceUri(resourceUri);
71
71
  const { apiClients } = useServer();
72
72
 
73
- if (!projectName || !packageName) {
73
+ if (!environmentName || !packageName) {
74
74
  throw new Error(
75
75
  "No project or package name provided. A resource URI must be provided.",
76
76
  );
@@ -80,7 +80,7 @@ export default function QueryResult({
80
80
  queryKey: [resourceUri, query, sourceName, queryName],
81
81
  queryFn: () =>
82
82
  apiClients.models.executeQueryModel(
83
- projectName,
83
+ environmentName,
84
84
  packageName,
85
85
  modelPath,
86
86
  {
@@ -104,7 +104,7 @@ export default function QueryResult({
104
104
  )}
105
105
  {isError && (
106
106
  <ApiErrorDisplay
107
- context={`${projectName} > ${packageName} > ${modelPath}`}
107
+ context={`${environmentName} > ${packageName} > ${modelPath}`}
108
108
  error={error}
109
109
  />
110
110
  )}
@@ -4,17 +4,17 @@ import React, {
4
4
  createContext,
5
5
  ReactNode,
6
6
  useContext,
7
- useMemo,
8
7
  useEffect,
8
+ useMemo,
9
9
  useState,
10
10
  } from "react";
11
11
  import {
12
12
  ConnectionsApi,
13
13
  DatabasesApi,
14
+ EnvironmentsApi,
14
15
  ModelsApi,
15
16
  NotebooksApi,
16
17
  PackagesApi,
17
- ProjectsApi,
18
18
  PublisherApi,
19
19
  WatchModeApi,
20
20
  } from "../client";
@@ -52,8 +52,8 @@ export interface ServerProviderProps {
52
52
  * Will send "Bearer 123" in the Authorization header.
53
53
  */
54
54
  getAccessToken?: () => Promise<string>;
55
- /** Whether the publisher should allow project and package management operations.
56
- * When false, users can only view and explore existing projects and packages.
55
+ /** Whether the publisher should allow environment and package management operations.
56
+ * When false, users can only view and explore existing environments and packages.
57
57
  * @default true
58
58
  */
59
59
  mutable?: boolean;
@@ -83,7 +83,7 @@ const getApiClients = (
83
83
  return {
84
84
  models: new ModelsApi(config, basePath, axiosInstance),
85
85
  publisher: new PublisherApi(config, basePath, axiosInstance),
86
- projects: new ProjectsApi(config, basePath, axiosInstance),
86
+ environments: new EnvironmentsApi(config, basePath, axiosInstance),
87
87
  packages: new PackagesApi(config, basePath, axiosInstance),
88
88
  notebooks: new NotebooksApi(config, basePath, axiosInstance),
89
89
  connections: new ConnectionsApi(config, basePath, axiosInstance),
@@ -32,16 +32,16 @@ export function ModelPicker({
32
32
  resourceUri,
33
33
  }: ModelPickerProps) {
34
34
  const {
35
- projectName: projectName,
35
+ environmentName: environmentName,
36
36
  packageName: packageName,
37
37
  versionId: versionId,
38
38
  } = parseResourceUri(resourceUri);
39
39
  const { apiClients } = useServer();
40
40
 
41
41
  const { data, isLoading, isSuccess, isError, error } = useQueryWithApiError({
42
- queryKey: ["models", projectName, packageName, versionId],
42
+ queryKey: ["models", environmentName, packageName, versionId],
43
43
  queryFn: () =>
44
- apiClients.models.listModels(projectName, packageName, versionId),
44
+ apiClients.models.listModels(environmentName, packageName, versionId),
45
45
  });
46
46
  const [selectedModels, setSelectedModels] = React.useState<string[]>(
47
47
  initialSelectedModels || [],
@@ -76,7 +76,7 @@ export function ModelPicker({
76
76
  return (
77
77
  <ApiErrorDisplay
78
78
  error={error}
79
- context={`${projectName} > ${packageName} > Model Picker`}
79
+ context={`${environmentName} > ${packageName} > Model Picker`}
80
80
  />
81
81
  );
82
82
  }
@@ -45,7 +45,7 @@ export default function Workbook({ workbookPath, resourceUri }: WorkbookProps) {
45
45
  const { server, getAccessToken } = useServer();
46
46
  const { apiClients } = useServer();
47
47
  const { workbookStorage } = useWorkbookStorage();
48
- const { projectName, packageName } = parseResourceUri(resourceUri);
48
+ const { environmentName, packageName } = parseResourceUri(resourceUri);
49
49
  const [success, setSuccess] = React.useState<string | undefined>(undefined);
50
50
  const [lastError, setLastError] = React.useState<string | undefined>(
51
51
  undefined,
@@ -113,7 +113,7 @@ export default function Workbook({ workbookPath, resourceUri }: WorkbookProps) {
113
113
  }
114
114
  setDeleteDialogOpen(false);
115
115
  // TODO(jjs) - on delete event
116
- navigate(`/${projectName}/${packageName}`);
116
+ navigate(`/${environmentName}/${packageName}`);
117
117
  };
118
118
 
119
119
  const handleDeleteCancel = () => {
@@ -155,7 +155,7 @@ export default function Workbook({ workbookPath, resourceUri }: WorkbookProps) {
155
155
  console.log("Fetching model from Publisher", model);
156
156
  promises.push(
157
157
  apiClients.models
158
- .getModel(projectName, packageName, model, undefined)
158
+ .getModel(environmentName, packageName, model, undefined)
159
159
  .then((data) => ({
160
160
  modelPath: model,
161
161
  sourceInfos: data.data.sourceInfos.map((source) =>
@@ -182,7 +182,7 @@ export default function Workbook({ workbookPath, resourceUri }: WorkbookProps) {
182
182
  fetchModels();
183
183
  // This function cannot depend on sourceAndPaths because it would cause an infinite loop.
184
184
  // eslint-disable-next-line react-hooks/exhaustive-deps
185
- }, [getAccessToken, workbookData, packageName, projectName, server]);
185
+ }, [getAccessToken, workbookData, packageName, environmentName, server]);
186
186
 
187
187
  React.useEffect(() => {
188
188
  if (!workbookPath) {
@@ -1,12 +1,12 @@
1
1
  export { AnalyzePackageButton } from "./AnalyzePackageButton";
2
2
  export { useRouterClickHandler } from "./click_helper";
3
+ export * from "./Environment";
3
4
  export * from "./filter";
4
5
  export * from "./Home";
5
6
  export * from "./Loading";
6
7
  export * from "./Model";
7
8
  export * from "./Notebook";
8
9
  export * from "./Package";
9
- export * from "./Project";
10
10
  export * from "./QueryResult";
11
11
  export * from "./RenderedResult";
12
12
  export { ServerProvider, useServer } from "./ServerProvider";
@@ -10,8 +10,8 @@ import { useDimensionFiltersQuery } from "./useDimensionFiltersQuery";
10
10
  * Configuration for dimensional filters
11
11
  */
12
12
  export interface DimensionFiltersConfig {
13
- /** Project name */
14
- project: string;
13
+ /** Environment name */
14
+ environment: string;
15
15
  /** Package name */
16
16
  package: string;
17
17
  /** Version ID (optional) */
@@ -37,7 +37,7 @@ export interface UseDimensionFiltersFromSpecOptions {
37
37
  * Combined hook that manages dimensional filters, data fetching, and query execution
38
38
  * from a single configuration object.
39
39
  *
40
- * @param config - Configuration containing project, package, dimension specs, and index limit
40
+ * @param config - Configuration containing environment, package, dimension specs, and index limit
41
41
  * @param queryLimit - Maximum number of results to return from query (default: 100)
42
42
  * @returns All state and methods needed for dimensional filtering UI
43
43
  */
@@ -69,7 +69,7 @@ export function useDimensionFiltersFromSpec(
69
69
  // The hook handles multiple source/model combos internally
70
70
  const { data, noRowsMatchedFilter, isLoading, isError, error, refetch } =
71
71
  useDimensionalFilterRangeData({
72
- project: config.project,
72
+ environment: config.environment,
73
73
  package: config.package,
74
74
  indexLimit: config.indexLimit,
75
75
  dimensionSpecs: config.dimensionSpecs,
@@ -83,7 +83,7 @@ export function useDimensionFiltersFromSpec(
83
83
  // Generate the embedded query result (uses primary source/model)
84
84
  const { embeddedQueryResult, queryString, executeQuery, canExecute } =
85
85
  useDimensionFiltersQuery({
86
- project: config.project,
86
+ environment: config.environment,
87
87
  package: config.package,
88
88
  model: primaryModel,
89
89
  source: primarySource,
@@ -7,8 +7,8 @@ import { FilterSelection, FilterValuePrimitive } from "./useDimensionFilters";
7
7
  * Parameters for the useDimensionFiltersQuery hook
8
8
  */
9
9
  export interface UseDimensionFiltersQueryParams {
10
- /** Project name */
11
- project: string;
10
+ /** Environment name */
11
+ environment: string;
12
12
  /** Package name */
13
13
  package: string;
14
14
  /** Model path */
@@ -218,7 +218,7 @@ function buildFilteredQuery(
218
218
  * });
219
219
  *
220
220
  * const { embeddedQueryResult, executeQuery, canExecute } = useDimensionFiltersQuery({
221
- * project: "my-project",
221
+ * environment: "my-environment",
222
222
  * package: "my-package",
223
223
  * model: "model.malloy",
224
224
  * source: "my_source",
@@ -242,7 +242,7 @@ export function useDimensionFiltersQuery(
242
242
  params: UseDimensionFiltersQueryParams,
243
243
  ): DimensionFiltersQueryResult {
244
244
  const {
245
- project,
245
+ environment,
246
246
  package: packageName,
247
247
  model,
248
248
  source,
@@ -266,11 +266,11 @@ export function useDimensionFiltersQuery(
266
266
  const resourceUri = useMemo(
267
267
  () =>
268
268
  encodeResourceUri({
269
- projectName: project,
269
+ environmentName: environment,
270
270
  packageName,
271
271
  modelPath: model,
272
272
  }),
273
- [project, packageName, model],
273
+ [environment, packageName, model],
274
274
  );
275
275
 
276
276
  // Check if query can be executed
@@ -80,8 +80,8 @@ export type DimensionValues = Map<string, DimensionValue[]>;
80
80
  * Parameters for the useDimensionalFilterRangeData hook
81
81
  */
82
82
  export interface UseDimensionalFilterRangeDataParams {
83
- /** Project name */
84
- project: string;
83
+ /** Environment name */
84
+ environment: string;
85
85
  /** Package name */
86
86
  package: string;
87
87
  /** List of dimension specifications (each includes source and model) */
@@ -611,13 +611,13 @@ function parseIndexQueryResult(
611
611
  * The hook groups dimension specs by source/model combination and runs separate
612
612
  * index queries for each group, then merges the results.
613
613
  *
614
- * @param params - Parameters including project, package, and dimension specs (each with source/model)
614
+ * @param params - Parameters including environment, package, and dimension specs (each with source/model)
615
615
  * @returns Query result with dimension values map, loading state, and error information
616
616
  *
617
617
  * @example
618
618
  * ```tsx
619
619
  * const { data, isLoading, error } = useDimensionalFilterRangeData({
620
- * project: "my-project",
620
+ * environment: "my-environment",
621
621
  * package: "my-package",
622
622
  * dimensionSpecs: [
623
623
  * { dimensionName: "category", filterType: "Star", source: "my_source", model: "model.malloy" },
@@ -632,7 +632,7 @@ export function useDimensionalFilterRangeData(
632
632
  params: UseDimensionalFilterRangeDataParams,
633
633
  ): DimensionalFilterRangeDataResult {
634
634
  const {
635
- project,
635
+ environment,
636
636
  package: packageName,
637
637
  dimensionSpecs,
638
638
  versionId,
@@ -695,7 +695,7 @@ export function useDimensionalFilterRangeData(
695
695
  const queryResult = useQueryWithApiError({
696
696
  queryKey: [
697
697
  "dimensionalFilter",
698
- project,
698
+ environment,
699
699
  packageName,
700
700
  dimensionSpecs,
701
701
  versionId,
@@ -716,7 +716,7 @@ export function useDimensionalFilterRangeData(
716
716
  const results = await Promise.all(
717
717
  queryConfigs.map(async (config) => {
718
718
  const response = await apiClients.models.executeQueryModel(
719
- project,
719
+ environment,
720
720
  packageName,
721
721
  config.model,
722
722
  {
@@ -19,14 +19,14 @@ export function useRawQueryData({
19
19
  enabled = true,
20
20
  resourceUri,
21
21
  }: UseRawQueryDataProps) {
22
- const { projectName, packageName, versionId } =
22
+ const { environmentName, packageName, versionId } =
23
23
  parseResourceUri(resourceUri);
24
24
  const { apiClients } = useServer();
25
25
 
26
26
  const { data, isSuccess, isError, error, isLoading } = useQueryWithApiError({
27
27
  queryKey: [
28
28
  "rawQueryData",
29
- projectName,
29
+ environmentName,
30
30
  packageName,
31
31
  modelPath,
32
32
  versionId,
@@ -36,7 +36,7 @@ export function useRawQueryData({
36
36
  ],
37
37
  queryFn: () =>
38
38
  apiClients.models.executeQueryModel(
39
- projectName,
39
+ environmentName,
40
40
  packageName,
41
41
  modelPath,
42
42
  {
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from "./components";
2
- export { default as ConnectionExplorer } from "./components/Project/ConnectionExplorer";
2
+ export { default as ConnectionExplorer } from "./components/Environment/ConnectionExplorer";
3
3
  export { useServer } from "./components/ServerProvider";
4
4
  export * from "./hooks";
5
5
  export { useRawQueryData } from "./hooks/useRawQueryData";
@@ -3,10 +3,11 @@ import { encodeResourceUri, parseResourceUri } from "./formatting";
3
3
 
4
4
  describe("parseResourceUri", () => {
5
5
  it("should parse a package URI", () => {
6
- const resourceUri = "publisher://projects/malloy-samples/packages/names";
6
+ const resourceUri =
7
+ "publisher://environments/malloy-samples/packages/names";
7
8
  const parsedResource = parseResourceUri(resourceUri);
8
9
  expect(parsedResource).toEqual({
9
- projectName: "malloy-samples",
10
+ environmentName: "malloy-samples",
10
11
  packageName: "names",
11
12
  connectionName: undefined,
12
13
  modelPath: undefined,
@@ -15,10 +16,10 @@ describe("parseResourceUri", () => {
15
16
  });
16
17
  it("should parse a connection URI", () => {
17
18
  const resourceUri =
18
- "publisher://projects/malloy-samples/connections/bigquery";
19
+ "publisher://environments/malloy-samples/connections/bigquery";
19
20
  const parsedResource = parseResourceUri(resourceUri);
20
21
  expect(parsedResource).toEqual({
21
- projectName: "malloy-samples",
22
+ environmentName: "malloy-samples",
22
23
  packageName: undefined,
23
24
  connectionName: "bigquery",
24
25
  modelPath: undefined,
@@ -28,10 +29,10 @@ describe("parseResourceUri", () => {
28
29
 
29
30
  it("should parse a modelPath URI", () => {
30
31
  const resourceUri =
31
- "publisher://projects/malloy-samples/packages/names/models/names1.malloynb";
32
+ "publisher://environments/malloy-samples/packages/names/models/names1.malloynb";
32
33
  const parsedResource = parseResourceUri(resourceUri);
33
34
  expect(parsedResource).toEqual({
34
- projectName: "malloy-samples",
35
+ environmentName: "malloy-samples",
35
36
  packageName: "names",
36
37
  connectionName: undefined,
37
38
  modelPath: "names1.malloynb",
@@ -41,13 +42,13 @@ describe("parseResourceUri", () => {
41
42
 
42
43
  it("should throw an error if the resource URI has the wrong protocol", () => {
43
44
  const resourceUri =
44
- "http://projects/malloy-samples/packages/names/models/names1.malloynb";
45
+ "http://environments/malloy-samples/packages/names/models/names1.malloynb";
45
46
  expect(() => parseResourceUri(resourceUri)).toThrow(
46
47
  `Failed to parse resource URI: ${resourceUri}`,
47
48
  );
48
49
  });
49
50
 
50
- it("should throw an error if the resource URI is missing the project name", () => {
51
+ it("should throw an error if the resource URI is missing the environment name", () => {
51
52
  const resourceUri = "publisher://";
52
53
  expect(() => parseResourceUri(resourceUri)).toThrow(
53
54
  /Failed to parse resource URI/,
@@ -56,10 +57,10 @@ describe("parseResourceUri", () => {
56
57
 
57
58
  it("should parse the optional versionId parameter if present", () => {
58
59
  const resourceUri =
59
- "publisher://projects/malloy-samples/packages/names?versionId=1.0.0";
60
+ "publisher://environments/malloy-samples/packages/names?versionId=1.0.0";
60
61
  const parsedResource = parseResourceUri(resourceUri);
61
62
  expect(parsedResource).toEqual({
62
- projectName: "malloy-samples",
63
+ environmentName: "malloy-samples",
63
64
  packageName: "names",
64
65
  connectionName: undefined,
65
66
  modelPath: undefined,
@@ -71,65 +72,65 @@ describe("parseResourceUri", () => {
71
72
  describe("encodeResourceUri", () => {
72
73
  it("should encode a package URI with no versionId", () => {
73
74
  const resourceUri = encodeResourceUri({
74
- projectName: "malloy-samples",
75
+ environmentName: "malloy-samples",
75
76
  packageName: "names",
76
77
  connectionName: undefined,
77
78
  modelPath: undefined,
78
79
  versionId: undefined,
79
80
  });
80
81
  expect(resourceUri).toEqual(
81
- "publisher://projects/malloy-samples/packages/names",
82
+ "publisher://environments/malloy-samples/packages/names",
82
83
  );
83
84
  });
84
85
 
85
86
  it("should encode a package URI with a versionId", () => {
86
87
  const resourceUri = encodeResourceUri({
87
- projectName: "malloy-samples",
88
+ environmentName: "malloy-samples",
88
89
  packageName: "names",
89
90
  versionId: "1.0.0",
90
91
  connectionName: undefined,
91
92
  modelPath: undefined,
92
93
  });
93
94
  expect(resourceUri).toEqual(
94
- "publisher://projects/malloy-samples/packages/names?versionId=1.0.0",
95
+ "publisher://environments/malloy-samples/packages/names?versionId=1.0.0",
95
96
  );
96
97
  });
97
98
 
98
99
  it("should encode a connection URI", () => {
99
100
  const resourceUri = encodeResourceUri({
100
- projectName: "malloy-samples",
101
+ environmentName: "malloy-samples",
101
102
  packageName: undefined,
102
103
  connectionName: "bigquery",
103
104
  modelPath: undefined,
104
105
  versionId: undefined,
105
106
  });
106
107
  expect(resourceUri).toEqual(
107
- "publisher://projects/malloy-samples/connections/bigquery",
108
+ "publisher://environments/malloy-samples/connections/bigquery",
108
109
  );
109
110
  });
110
111
 
111
112
  it("should encode a modelPath URI", () => {
112
113
  const resourceUri = encodeResourceUri({
113
- projectName: "malloy-samples",
114
+ environmentName: "malloy-samples",
114
115
  packageName: "names",
115
116
  connectionName: undefined,
116
117
  modelPath: "names1.malloynb",
117
118
  versionId: undefined,
118
119
  });
119
120
  expect(resourceUri).toEqual(
120
- "publisher://projects/malloy-samples/packages/names/models/names1.malloynb",
121
+ "publisher://environments/malloy-samples/packages/names/models/names1.malloynb",
121
122
  );
122
123
  });
123
124
 
124
- it("should throw an error if the resource URI is missing the project name", () => {
125
+ it("should throw an error if the resource URI is missing the environment name", () => {
125
126
  expect(() =>
126
127
  encodeResourceUri({
127
- projectName: "",
128
+ environmentName: "",
128
129
  packageName: "names",
129
130
  connectionName: undefined,
130
131
  modelPath: undefined,
131
132
  versionId: undefined,
132
133
  }),
133
- ).toThrow(/Failed to encode resource URI, missing project name/);
134
+ ).toThrow(/Failed to encode resource URI, missing environment name/);
134
135
  });
135
136
  });
@@ -1,5 +1,5 @@
1
1
  export type ParsedResource = {
2
- projectName: string;
2
+ environmentName: string;
3
3
  packageName?: string | undefined;
4
4
  connectionName?: string | undefined;
5
5
  versionId?: string | undefined;
@@ -15,8 +15,9 @@ export const parseResourceUri = (resourceUri: string) => {
15
15
  const pathParts = (parsedUri.hostname + parsedUri.pathname).split("/");
16
16
  for (let i = 0; i < pathParts.length; i += 2) {
17
17
  const part = pathParts[i];
18
- if (part === "projects") {
19
- parsedResource.projectName = decodeURI(pathParts[i + 1]) || undefined;
18
+ if (part === "environments") {
19
+ parsedResource.environmentName =
20
+ decodeURI(pathParts[i + 1]) || undefined;
20
21
  } else if (part === "packages") {
21
22
  parsedResource.packageName = decodeURI(pathParts[i + 1]) || undefined;
22
23
  } else if (part === "connections") {
@@ -30,19 +31,19 @@ export const parseResourceUri = (resourceUri: string) => {
30
31
 
31
32
  parsedResource.versionId =
32
33
  parsedUri.searchParams.get("versionId") || undefined;
33
- if (!parsedResource.projectName) {
34
+ if (!parsedResource.environmentName) {
34
35
  throw new Error(`Failed to parse resource URI: ${resourceUri}`);
35
36
  }
36
37
  return parsedResource;
37
38
  };
38
39
 
39
40
  export const encodeResourceUri = (resource: ParsedResource) => {
40
- if (!resource.projectName) {
41
+ if (!resource.environmentName) {
41
42
  throw new Error(
42
- `Failed to encode resource URI, missing project name: ${resource}`,
43
+ `Failed to encode resource URI, missing environment name: ${resource}`,
43
44
  );
44
45
  }
45
- let uri = `publisher://projects/${resource.projectName}`;
46
+ let uri = `publisher://environments/${resource.environmentName}`;
46
47
  if (resource.packageName) {
47
48
  uri += `/packages/${resource.packageName}`;
48
49
  }
@@ -1,11 +1,15 @@
1
1
  import { describe, expect, it } from "bun:test";
2
- import { getProjectDescription, generateProjectReadme } from "./parsing";
2
+ import {
3
+ generateEnvironmentReadme,
4
+ getEnvironmentDescription,
5
+ } from "./parsing";
3
6
 
4
- describe("getProjectDescription", () => {
7
+ describe("getEnvironmentDescription", () => {
5
8
  it("should return the first paragraph of the README", () => {
6
- const readme = "# Project Description\nThis is a project description";
7
- expect(getProjectDescription(readme)).toBe(
8
- "Project Description\nThis is a project description",
9
+ const readme =
10
+ "# Environment Description\nThis is an environment description";
11
+ expect(getEnvironmentDescription(readme)).toBe(
12
+ "Environment Description\nThis is an environment description",
9
13
  );
10
14
  });
11
15
 
@@ -14,42 +18,42 @@ describe("getProjectDescription", () => {
14
18
  const readme = `${longDescription}`;
15
19
  // 5 characters per word + space, so 20 words = 120 characters
16
20
  const truncatedDescription = Array(20).fill("abcde").join(" ") + "...";
17
- expect(getProjectDescription(readme)).toBe(truncatedDescription);
21
+ expect(getEnvironmentDescription(readme)).toBe(truncatedDescription);
18
22
  });
19
23
 
20
24
  it("should return a placeholder description if the README is empty", () => {
21
25
  const readme = "";
22
- expect(getProjectDescription(readme)).toBe(
26
+ expect(getEnvironmentDescription(readme)).toBe(
23
27
  "Explore semantic models, run queries, and build dashboards",
24
28
  );
25
29
  });
26
30
  });
27
31
 
28
- describe("generateProjectReadme", () => {
32
+ describe("generateEnvironmentReadme", () => {
29
33
  it("should preserve the existing readme if it exists", () => {
30
- const project = {
31
- name: "Test Project",
34
+ const environment = {
35
+ name: "Test Environment",
32
36
  readme: "# Test Readme",
33
37
  };
34
- expect(generateProjectReadme(project)).toBe("# Test Readme");
38
+ expect(generateEnvironmentReadme(environment)).toBe("# Test Readme");
35
39
  });
36
40
 
37
- it("should generate a project readme with the description if it does not exist", () => {
38
- const project = {
39
- name: "Test Project",
41
+ it("should generate an environment readme with the description if it does not exist", () => {
42
+ const environment = {
43
+ name: "Test Environment",
40
44
  readme: "",
41
45
  };
42
- expect(generateProjectReadme(project, "Test Description")).toBe(
43
- "# Test Project\n\nTest Description",
46
+ expect(generateEnvironmentReadme(environment, "Test Description")).toBe(
47
+ "# Test Environment\n\nTest Description",
44
48
  );
45
49
  });
46
50
 
47
51
  it("should insert the description in the existing readme if both exist", () => {
48
- const project = {
49
- name: "Test Project",
52
+ const environment = {
53
+ name: "Test Environment",
50
54
  readme: "# Test Readme\n\nOld Description\n\nMore stuff",
51
55
  };
52
- expect(generateProjectReadme(project, "New Description")).toBe(
56
+ expect(generateEnvironmentReadme(environment, "New Description")).toBe(
53
57
  "# Test Readme\n\nNew Description\n\nMore stuff",
54
58
  );
55
59
  });
@@ -1,5 +1,7 @@
1
1
  // Helper function to extract a brief description from README content
2
- export const getProjectDescription = (readme: string | undefined): string => {
2
+ export const getEnvironmentDescription = (
3
+ readme: string | undefined,
4
+ ): string => {
3
5
  if (!readme) {
4
6
  return "Explore semantic models, run queries, and build dashboards";
5
7
  }
@@ -28,19 +30,19 @@ export const getProjectDescription = (readme: string | undefined): string => {
28
30
  return truncated.join(" ") + "...";
29
31
  };
30
32
 
31
- export const generateProjectReadme = (
32
- project: {
33
+ export const generateEnvironmentReadme = (
34
+ environment: {
33
35
  name: string;
34
36
  readme?: string;
35
37
  },
36
38
  description?: string,
37
39
  ): string => {
38
- const readmeLines = (project.readme || undefined)?.split("\n") ?? [];
40
+ const readmeLines = (environment.readme || undefined)?.split("\n") ?? [];
39
41
  if (readmeLines.length === 0) {
40
- readmeLines.push(`# ${project.name}`);
42
+ readmeLines.push(`# ${environment.name}`);
41
43
  readmeLines.push("");
42
44
  }
43
- if ((project.readme?.length ?? 0) > 0 && description) {
45
+ if ((environment.readme?.length ?? 0) > 0 && description) {
44
46
  readmeLines.splice(2, 1, description);
45
47
  } else if (description) {
46
48
  readmeLines.push(description);