quasar-ui-danx 0.4.57 → 0.4.60

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.4.57",
3
+ "version": "0.4.60",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -10,7 +10,10 @@
10
10
  "types": "types/index.d.ts",
11
11
  "scripts": {
12
12
  "dev": "cd dev && quasar dev && cd ..",
13
- "build": "vite build",
13
+ "clean": "rimraf dist",
14
+ "build:types": "tsc -p tsconfig.build.json",
15
+ "build:bundle": "vite build",
16
+ "build": "yarn clean && yarn build:types && yarn build:bundle",
14
17
  "preview": "vite preview",
15
18
  "postversion": "yarn build && npm publish && cd .. && git add ui && git commit -m \"v$npm_package_version\" && git tag \"v$npm_package_version\" && git push"
16
19
  },
@@ -11,7 +11,7 @@
11
11
  </RenderedForm>
12
12
  </template>
13
13
  <script setup lang="ts">
14
- import { Ref, ref, watch } from "vue";
14
+ import { computed, Ref, ref, watch } from "vue";
15
15
  import { ActionTargetItem, AnyObject, Form, ResourceAction } from "../../../types";
16
16
  import RenderedForm from "./RenderedForm.vue";
17
17
 
@@ -59,8 +59,21 @@ watch(() => props.target, (target: ActionTargetItem) => {
59
59
  }
60
60
  });
61
61
 
62
+ const isValid = computed(() => {
63
+ for (let field of props.form.fields) {
64
+ const value = input.value[field.name];
65
+
66
+ if (field.required && !value && value !== false) {
67
+ return false;
68
+ }
69
+ }
70
+ return true;
71
+ });
72
+
62
73
  async function onUpdate() {
63
- await props.action.trigger(props.target, input.value);
64
- emit("saved");
74
+ if (isValid.value) {
75
+ await props.action.trigger(props.target, input.value);
76
+ emit("saved");
77
+ }
65
78
  }
66
79
  </script>
@@ -80,7 +80,6 @@
80
80
  :class="editClass"
81
81
  :size="size"
82
82
  :disabled="editDisabled"
83
- class="opacity-0 group-hover:opacity-100 transition-all"
84
83
  :show-icon="EditIcon"
85
84
  :hide-icon="DoneEditingIcon"
86
85
  :tooltip="editDisabled ? 'You are not allowed to edit' : ''"
@@ -1,4 +1,4 @@
1
- import { computed, ref, shallowRef, watch } from "vue";
1
+ import { computed, Ref, ref, shallowRef, watch } from "vue";
2
2
  import { RouteParams, Router } from "vue-router";
3
3
  import { danxOptions } from "../../config";
4
4
  import { getItem, latestCallOnly, setItem, storeObject, waitForRef } from "../../helpers";
@@ -10,8 +10,7 @@ import {
10
10
  ListControlsFilter,
11
11
  ListControlsOptions,
12
12
  ListControlsPagination,
13
- PagedItems,
14
- Ref
13
+ PagedItems
15
14
  } from "../../types";
16
15
  import { getFilterFromUrl } from "./listHelpers";
17
16
 
@@ -1,59 +1,58 @@
1
1
  <template>
2
- <QBtn
3
- :loading="isSaving"
4
- class="shadow-none py-0"
5
- :class="buttonClass"
6
- :disable="disabled"
7
- @click="()=> onAction()"
8
- >
9
- <div class="flex items-center flex-nowrap">
10
- <component
11
- :is="icon || typeOptions.icon"
12
- class="transition-all"
13
- :class="resolvedIconClass"
14
- />
15
- <slot>
16
- <div
17
- v-if="label || label === 0"
18
- class="ml-2"
19
- :class="labelClass"
20
- >
21
- {{ label }}
22
- </div>
23
- </slot>
24
- </div>
25
- <QTooltip
26
- v-if="tooltip"
27
- class="whitespace-nowrap"
28
- :class="tooltipClass"
29
- >
30
- <slot name="tooltip">
31
- {{ tooltip }}
32
- </slot>
33
- </QTooltip>
34
- <QMenu
35
- v-if="isConfirming"
36
- :model-value="true"
37
- >
38
- <div class="p-4 bg-slate-600">
39
- <div>{{ confirmText }}</div>
40
- <div class="flex items-center flex-nowrap mt-2">
41
- <div class="flex-grow">
42
- <ActionButton
43
- type="cancel"
44
- color="gray"
45
- @click="isConfirming = false"
46
- />
47
- </div>
48
- <ActionButton
49
- type="confirm"
50
- color="green"
51
- @click="()=> onAction(true)"
52
- />
53
- </div>
54
- </div>
55
- </QMenu>
56
- </QBtn>
2
+ <QBtn
3
+ :loading="isSaving"
4
+ class="shadow-none py-0"
5
+ :class="buttonClass"
6
+ :disable="disabled"
7
+ @click="()=> onAction()"
8
+ >
9
+ <div class="flex items-center flex-nowrap">
10
+ <component
11
+ :is="icon || typeOptions.icon"
12
+ class="transition-all"
13
+ :class="resolvedIconClass"
14
+ />
15
+ <div
16
+ v-if="label || label === 0"
17
+ class="ml-2"
18
+ :class="labelClass"
19
+ >
20
+ {{ label }}
21
+ </div>
22
+ <slot />
23
+ </div>
24
+ <QTooltip
25
+ v-if="tooltip"
26
+ class="whitespace-nowrap"
27
+ :class="tooltipClass"
28
+ >
29
+ <slot name="tooltip">
30
+ {{ tooltip }}
31
+ </slot>
32
+ </QTooltip>
33
+ <QMenu
34
+ v-if="isConfirming"
35
+ :model-value="true"
36
+ >
37
+ <div class="p-4 bg-slate-600">
38
+ <div>{{ confirmText }}</div>
39
+ <div class="flex items-center flex-nowrap mt-2">
40
+ <div class="flex-grow">
41
+ <ActionButton
42
+ type="cancel"
43
+ color="gray"
44
+ @click="isConfirming = false"
45
+ />
46
+ </div>
47
+ <ActionButton
48
+ type="confirm"
49
+ color="green"
50
+ @click="()=> onAction(true)"
51
+ />
52
+ </div>
53
+ </div>
54
+ </QMenu>
55
+ </QBtn>
57
56
  </template>
58
57
  <script setup lang="ts">
59
58
  import {
@@ -63,6 +62,7 @@ import {
63
62
  FaSolidCopy as CopyIcon,
64
63
  FaSolidFileExport as ExportIcon,
65
64
  FaSolidFileImport as ImportIcon,
65
+ FaSolidMinus as MinusIcon,
66
66
  FaSolidPause as PauseIcon,
67
67
  FaSolidPencil as EditIcon,
68
68
  FaSolidPlay as PlayIcon,
@@ -74,8 +74,8 @@ import { computed, ref } from "vue";
74
74
  import { ActionTarget, ResourceAction } from "../../../types";
75
75
 
76
76
  export interface ActionButtonProps {
77
- type?: "trash" | "trash-red" | "create" | "edit" | "copy" | "play" | "stop" | "pause" | "refresh" | "confirm" | "cancel" | "export" | "import";
78
- color?: "red" | "blue" | "sky" | "sky-invert" | "green" | "green-invert" | "lime" | "white" | "gray";
77
+ type?: "trash" | "create" | "edit" | "copy" | "play" | "stop" | "pause" | "refresh" | "confirm" | "cancel" | "export" | "import" | "minus";
78
+ color?: "red" | "blue" | "sky" | "sky-invert" | "green" | "green-invert" | "lime" | "white" | "gray" | "yellow" | "orange";
79
79
  size?: "xxs" | "xs" | "sm" | "md" | "lg";
80
80
  icon?: object | string;
81
81
  iconClass?: string;
@@ -159,6 +159,10 @@ const colorClass = computed(() => {
159
159
  return "text-sky-400 bg-sky-800 hover:bg-sky-900";
160
160
  case "white":
161
161
  return "text-white bg-gray-800 hover:bg-gray-200";
162
+ case "yellow":
163
+ return "text-yellow-300 bg-yellow-800 hover:bg-yellow-700";
164
+ case "orange":
165
+ return "text-orange-400 bg-orange-900 hover:bg-orange-800";
162
166
  case "gray":
163
167
  return "text-slate-200 bg-slate-800 hover:bg-slate-900";
164
168
  default:
@@ -194,6 +198,8 @@ const typeOptions = computed(() => {
194
198
  return { icon: PauseIcon };
195
199
  case "refresh":
196
200
  return { icon: RefreshIcon };
201
+ case "minus":
202
+ return { icon: MinusIcon };
197
203
  default:
198
204
  return { icon: EditIcon };
199
205
  }
@@ -0,0 +1,29 @@
1
+ import { ref, shallowRef } from "vue";
2
+ import { ActionStore, ActionTargetItem, ListControlsRoutes } from "../types";
3
+
4
+ export function useActionStore(routes: ListControlsRoutes): ActionStore {
5
+ const listItems = shallowRef<ActionTargetItem[]>([]);
6
+ const isRefreshing = ref(false);
7
+ const hasLoadedItems = ref(false);
8
+
9
+ async function loadItems() {
10
+ if (hasLoadedItems.value) return;
11
+ await refreshItems();
12
+ hasLoadedItems.value = true;
13
+ }
14
+
15
+ async function refreshItems() {
16
+ if (isRefreshing.value) return;
17
+ isRefreshing.value = true;
18
+ listItems.value = (await routes.list({ sort: [{ column: "name" }] })).data || [];
19
+ isRefreshing.value = false;
20
+ }
21
+
22
+ return {
23
+ listItems,
24
+ isRefreshing,
25
+ hasLoadedItems,
26
+ loadItems,
27
+ refreshItems
28
+ };
29
+ }
@@ -1,64 +1,65 @@
1
1
  import { useGeolocation } from "@vueuse/core";
2
- import { computed } from "vue";
2
+ import { computed, ShallowRef } from "vue";
3
+ import { Ref } from "vue-demi";
3
4
  import { sleep } from "./utils";
4
5
 
5
6
  let isLoaded = false;
6
7
  let hasAlreadyWaited = false;
7
- let geolocationError = null;
8
- let hasLocation = null;
9
- let geolocation = null;
8
+ let geolocationError: ShallowRef<GeolocationPositionError | null> | null = null;
9
+ let hasLocation: Ref<number | null> | null = null;
10
+ let geolocation: Ref<GeolocationCoordinates> | null = null;
10
11
 
11
12
  export function useCompatibility(requestLocation = true) {
12
- if (!isLoaded && requestLocation) {
13
- const { coords, error, locatedAt } = useGeolocation();
14
- geolocationError = error;
15
- hasLocation = locatedAt;
16
- geolocation = coords;
17
- isLoaded = true;
18
- }
13
+ if (!isLoaded && requestLocation) {
14
+ const { coords, error, locatedAt } = useGeolocation();
15
+ geolocationError = error;
16
+ hasLocation = locatedAt;
17
+ geolocation = coords;
18
+ isLoaded = true;
19
+ }
19
20
 
20
- const isLocationSupported = "geolocation" in navigator;
21
+ const isLocationSupported = "geolocation" in navigator;
21
22
 
22
- const location = computed(() => {
23
- if (hasLocation?.value) {
24
- return geolocation?.value;
25
- }
26
- return null;
27
- });
23
+ const location = computed(() => {
24
+ if (hasLocation?.value) {
25
+ return geolocation?.value;
26
+ }
27
+ return null;
28
+ });
28
29
 
29
- const isCompatible = computed(() => !geolocationError?.value && !!hasLocation?.value);
30
+ const isCompatible = computed(() => !geolocationError?.value && !!hasLocation?.value);
30
31
 
31
- /**
32
- * Wait for location to be available and returns the location when it is or null after the wait period times out.
33
- * @param maxWait
34
- */
35
- const waitForLocation = async (maxWait = 3000) => {
36
- // We only should wait once, if we already waited and failed, its unlikely the location will be available at a
37
- // later time
38
- if (hasAlreadyWaited) {
39
- return location;
40
- }
32
+ /**
33
+ * Wait for location to be available and returns the location when it is or null after the wait period times out.
34
+ * @param maxWait
35
+ */
36
+ const waitForLocation = async (maxWait = 3000) => {
37
+ // We only should wait once, if we already waited and failed, its unlikely the location will be available at a
38
+ // later time
39
+ if (hasAlreadyWaited) {
40
+ return location;
41
+ }
41
42
 
42
- hasAlreadyWaited = true;
43
- let waitTime = 0;
44
- while (!location.value) {
45
- await sleep(100);
46
- waitTime += 100;
43
+ hasAlreadyWaited = true;
44
+ let waitTime = 0;
45
+ while (!location.value) {
46
+ await sleep(100);
47
+ waitTime += 100;
47
48
 
48
- if (waitTime > maxWait) {
49
- return null;
50
- }
51
- }
49
+ if (waitTime > maxWait) {
50
+ return null;
51
+ }
52
+ }
52
53
 
53
- return location;
54
- };
54
+ return location;
55
+ };
55
56
 
56
- return {
57
- isLocationSupported,
58
- isCompatible,
59
- geolocationError,
60
- hasLocation,
61
- location,
62
- waitForLocation
63
- };
57
+ return {
58
+ isLocationSupported,
59
+ isCompatible,
60
+ geolocationError,
61
+ hasLocation,
62
+ location,
63
+ waitForLocation
64
+ };
64
65
  }
@@ -1,5 +1,6 @@
1
+ import { DateTime } from "luxon";
1
2
  import { parseDateTime } from "./formats";
2
3
 
3
4
  export function diffInDays(date1: string, date2: string) {
4
- return parseDateTime(date2).diff(parseDateTime(date1), ["days"]).days;
5
+ return parseDateTime(date2)?.diff(parseDateTime(date1) || DateTime.now(), ["days"]).days;
5
6
  }
@@ -1,4 +1,5 @@
1
1
  export * from "./actions";
2
+ export * from "./actionStore";
2
3
  export * from "./app";
3
4
  export * from "./array";
4
5
  export * from "./compatibility";
@@ -1,8 +1,8 @@
1
1
  import { FilterGroup, ListController, ListControlsRoutes } from "src/types/controls";
2
2
  import { FormField } from "src/types/forms";
3
3
  import { TableColumn } from "src/types/tables";
4
- import { VNode } from "vue";
5
- import { AnyObject, ComputedRef, TypedObject } from "./shared";
4
+ import { ComputedRef, Ref, ShallowRef, VNode } from "vue";
5
+ import { AnyObject, TypedObject } from "./shared";
6
6
 
7
7
  export interface ActionTargetItem extends TypedObject {
8
8
  isSaving?: boolean;
@@ -58,6 +58,14 @@ export interface ResourceAction<T = ActionTargetItem> extends ActionOptions<T> {
58
58
  __type: string;
59
59
  }
60
60
 
61
+ export interface ActionStore {
62
+ listItems: ShallowRef<ActionTargetItem[]>;
63
+ isRefreshing: Ref<boolean>;
64
+ hasLoadedItems: Ref<boolean>;
65
+ loadItems: () => Promise<void>;
66
+ refreshItems: () => Promise<void>;
67
+ }
68
+
61
69
  export interface ActionController<T = ActionTargetItem> {
62
70
  // Actions
63
71
  action?: (actionName: string, target?: T | null, input?: any) => Promise<any | void>;
@@ -68,8 +76,9 @@ export interface ActionController<T = ActionTargetItem> {
68
76
  batchActions?: ResourceAction[];
69
77
  menuActions?: ResourceAction[];
70
78
  columns?: TableColumn[];
71
- filters?: ComputedRef<FilterGroup[]>;
79
+ filters?: ComputedRef<FilterGroup[]> | FilterGroup[];
72
80
  fields?: FormField[];
73
81
  panels?: ActionPanel[];
74
82
  routes?: ListControlsRoutes;
83
+ store?: ActionStore;
75
84
  }
@@ -1,6 +1,7 @@
1
1
  import { RequestCallOptions } from "src/types/requests";
2
+ import { ComputedRef, Ref, ShallowRef } from "vue";
2
3
  import { ActionOptions, ActionTargetItem, ResourceAction } from "./actions";
3
- import { AnyObject, ComputedRef, LabelValueItem, Ref } from "./shared";
4
+ import { AnyObject, LabelValueItem } from "./shared";
4
5
 
5
6
  export interface ListControlsFilter {
6
7
  [key: string]: object | object[] | null | undefined | string | number | boolean;
@@ -52,6 +53,7 @@ export interface ListControlsOptions {
52
53
 
53
54
  export interface ListControlsPagination {
54
55
  __sort?: object[] | null;
56
+ sort?: object[] | null;
55
57
  sortBy?: string | null;
56
58
  descending?: boolean;
57
59
  page?: number;
@@ -77,7 +79,7 @@ export interface PagedItems<T = ActionTargetItem> {
77
79
  export interface ListController<T = ActionTargetItem> {
78
80
  name: string;
79
81
  label: string;
80
- pagedItems: Ref<PagedItems<T> | null>;
82
+ pagedItems: ShallowRef<PagedItems<T> | null>;
81
83
  activeFilter: Ref<ListControlsFilter>;
82
84
  globalFilter: Ref<ListControlsFilter>;
83
85
  filterActiveCount: ComputedRef<number>;
@@ -14,12 +14,3 @@ export interface LabelValueItem {
14
14
  label: string;
15
15
  value: string | number | boolean;
16
16
  }
17
-
18
- /** Define Vue 3 Types here for better type checking in PHPStorm */
19
- export interface Ref<T = any> {
20
- value: T;
21
- }
22
-
23
- export interface ComputedRef<T = any> {
24
- readonly value: T;
25
- }
@@ -0,0 +1,48 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Compile down to ESNext (or choose your target version)
4
+ "target": "esnext",
5
+ // Use ES modules
6
+ "module": "esnext",
7
+ // Library files to be included in the compilation
8
+ "lib": [
9
+ "dom",
10
+ "esnext"
11
+ ],
12
+ // Generate corresponding '.d.ts' file
13
+ "declaration": true,
14
+ // Output directory for the compiled files
15
+ "outDir": "./dist",
16
+ // Root directory of your source files
17
+ "rootDir": "./src",
18
+ // Enable all strict type-checking options
19
+ "strict": true,
20
+ // Enables compatibility with Babel-style module imports
21
+ "esModuleInterop": true,
22
+ // Skip type checking of all declaration files (*.d.ts)
23
+ "skipLibCheck": true,
24
+ // Disallow inconsistently-cased references to the same file
25
+ "forceConsistentCasingInFileNames": true,
26
+ // Resolve modules using Node.js style
27
+ "moduleResolution": "node",
28
+ "resolveJsonModule": true,
29
+ // Allow default imports from modules with no default export
30
+ "allowSyntheticDefaultImports": true,
31
+ // Enables experimental support for decorators
32
+ "experimentalDecorators": true,
33
+ // Enables source map generation for the compiled files (useful for debugging)
34
+ "sourceMap": true,
35
+ // Base directory to resolve non-relative module names,
36
+ "baseUrl": "./"
37
+ },
38
+ "include": [
39
+ "src/**/*.ts",
40
+ "src/**/*.vue",
41
+ "src/**/*.svg",
42
+ "types/**/*.d.ts"
43
+ ],
44
+ "exclude": [
45
+ "dist",
46
+ "**/*.spec.ts"
47
+ ]
48
+ }
package/tsconfig.json CHANGED
@@ -1,49 +1,11 @@
1
1
  {
2
+ "extends": "./tsconfig.build.json",
2
3
  "compilerOptions": {
3
- // Compile down to ESNext (or choose your target version)
4
- "target": "esnext",
5
- // Use ES modules
6
- "module": "esnext",
7
- // Library files to be included in the compilation
8
- "lib": [
9
- "dom",
10
- "esnext"
11
- ],
12
- // Generate corresponding '.d.ts' file
13
- "declaration": true,
14
- // Output directory for the compiled files
15
- "outDir": "./dist",
16
- // Root directory of your source files
17
- "rootDir": "./src",
18
- // Enable all strict type-checking options
19
- "strict": true,
20
- // Enables compatibility with Babel-style module imports
21
- "esModuleInterop": true,
22
- // Skip type checking of all declaration files (*.d.ts)
23
- "skipLibCheck": true,
24
- // Disallow inconsistently-cased references to the same file
25
- "forceConsistentCasingInFileNames": true,
26
- // Resolve modules using Node.js style
27
- "moduleResolution": "node",
28
- "resolveJsonModule": true,
29
- // Allow default imports from modules with no default export
30
- "allowSyntheticDefaultImports": true,
31
- // Enables experimental support for decorators
32
- "experimentalDecorators": true,
33
- // Enables source map generation for the compiled files (useful for debugging)
34
- "sourceMap": true,
35
- // Base directory to resolve non-relative module names,
36
- "baseUrl": "./",
37
- "paths": {}
38
- },
39
- "include": [
40
- "src/**/*.ts",
41
- "src/**/*.vue",
42
- "src/**/*.svg",
43
- "types/**/*.d.ts"
44
- ],
45
- "exclude": [
46
- "dist",
47
- "**/*.spec.ts"
48
- ]
4
+ "paths": {
5
+ "vue": [
6
+ "../../gpt-manager/spa/node_modules/vue"
7
+ ]
8
+ }
9
+ }
49
10
  }
11
+
package/vite.config.js CHANGED
@@ -1,39 +1,39 @@
1
- import vue from '@vitejs/plugin-vue';
2
- import { resolve } from 'path';
3
- import { defineConfig } from 'vite';
4
- import svgLoader from 'vite-svg-loader';
1
+ import vue from "@vitejs/plugin-vue";
2
+ import { resolve } from "path";
3
+ import { defineConfig } from "vite";
4
+ import svgLoader from "vite-svg-loader";
5
5
 
6
6
  export default defineConfig({
7
- plugins: [vue(), svgLoader()],
8
- resolve: {
9
- extensions: ['.mjs', '.js', '.ts', '.mts', '.jsx', '.tsx', '.json', '.vue', '.svg']
10
- },
11
- build: {
12
- sourcemap: true,
13
- lib: {
14
- entry: resolve(__dirname, './src/index.esm.js'),
15
- name: 'Danx',
16
- // the proper extensions will be added
17
- fileName: (format) => `danx.${format}.js`
18
- },
19
- // Add rollupOptions only if you need to customize the build further
20
- rollupOptions: {
21
- // Externalize deps that shouldn't be bundled into your library
22
- external: ['vue', 'quasar'],
23
- output: {
24
- // Provide globals here
25
- globals: {
26
- vue: 'Vue',
27
- quasar: 'Quasar'
28
- }
29
- }
30
- }
31
- },
32
- css: {
33
- preprocessorOptions: {
34
- scss: {
35
- additionalData: `@import "./src/styles/index.scss";`
36
- }
37
- }
38
- }
7
+ plugins: [vue(), svgLoader()],
8
+ resolve: {
9
+ extensions: [".mjs", ".js", ".ts", ".mts", ".jsx", ".tsx", ".json", ".vue", ".svg"]
10
+ },
11
+ build: {
12
+ sourcemap: true,
13
+ lib: {
14
+ entry: resolve(__dirname, "./src/index.esm.js"),
15
+ name: "Danx",
16
+ // the proper extensions will be added
17
+ fileName: (format) => `danx.${format}.js`
18
+ },
19
+ // Add rollupOptions only if you need to customize the build further
20
+ rollupOptions: {
21
+ // Externalize deps that shouldn't be bundled into your library
22
+ external: ["vue", "quasar"],
23
+ output: {
24
+ // Provide globals here
25
+ globals: {
26
+ vue: "Vue",
27
+ quasar: "Quasar"
28
+ }
29
+ }
30
+ }
31
+ },
32
+ css: {
33
+ preprocessorOptions: {
34
+ scss: {
35
+ additionalData: `@import "./src/styles/index.scss";`
36
+ }
37
+ }
38
+ }
39
39
  });