quasar-ui-danx 0.4.20 → 0.4.22

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.20",
3
+ "version": "0.4.22",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <QToggle
3
- :data-testid="'boolean-field-' + field.id"
3
+ :data-testid="'boolean-field-' + (name || label)"
4
4
  :model-value="modelValue || (toggleIndeterminate ? modelValue : false)"
5
5
  :disable="disable || readonly"
6
6
  :toggle-indeterminate="toggleIndeterminate"
@@ -8,37 +8,39 @@
8
8
  @update:model-value="$emit('update:model-value', $event)"
9
9
  >
10
10
  <FieldLabel
11
- :field="{...field, label: label || field.label}"
11
+ :label="label || name"
12
+ :name="name"
12
13
  :show-name="showName"
13
14
  :class="labelClass"
14
15
  />
15
16
  </QToggle>
16
17
  </template>
17
18
 
18
- <script setup>
19
+ <script setup lang="ts">
19
20
  import FieldLabel from "./FieldLabel";
20
21
 
21
22
  defineEmits(["update:model-value"]);
22
23
  defineProps({
23
- label: {
24
- type: String,
25
- default: null
26
- },
27
- modelValue: {
28
- type: [Boolean],
29
- default: undefined
30
- },
31
- field: {
32
- type: Object,
33
- required: true
34
- },
35
- labelClass: {
36
- type: String,
37
- default: "text-sm"
38
- },
39
- showName: Boolean,
40
- toggleIndeterminate: Boolean,
41
- disable: Boolean,
42
- readonly: Boolean
24
+ label: {
25
+ type: String,
26
+ default: null
27
+ },
28
+ name: {
29
+ type: String,
30
+ default: null
31
+ },
32
+ required: Boolean,
33
+ modelValue: {
34
+ type: Boolean,
35
+ default: undefined
36
+ },
37
+ labelClass: {
38
+ type: String,
39
+ default: "text-sm"
40
+ },
41
+ showName: Boolean,
42
+ toggleIndeterminate: Boolean,
43
+ disable: Boolean,
44
+ readonly: Boolean
43
45
  });
44
46
  </script>
@@ -1,26 +1,22 @@
1
1
  <template>
2
2
  <NumberField
3
- :field="field"
3
+ v-bind="$props"
4
4
  :precision="0"
5
5
  :model-value="modelValue"
6
- :show-name="showName"
7
6
  @update:model-value="$emit('update:model-value', $event)"
8
7
  />
9
8
  </template>
10
9
 
11
- <script setup>
10
+ <script setup lang="ts">
11
+ import { NumberFieldProps } from "../../../../types";
12
12
  import NumberField from "./NumberField";
13
13
 
14
14
  defineEmits(["update:model-value"]);
15
- defineProps({
16
- modelValue: {
17
- type: [String, Number],
18
- default: null
19
- },
20
- field: {
21
- type: Object,
22
- required: true
23
- },
24
- showName: Boolean
15
+ withDefaults(defineProps<NumberFieldProps>(), {
16
+ modelValue: "",
17
+ label: undefined,
18
+ delay: 1000,
19
+ min: undefined,
20
+ max: undefined
25
21
  });
26
22
  </script>
@@ -4,14 +4,25 @@
4
4
  {{ label }}
5
5
  </div>
6
6
  <div :class="valueClass">
7
- <a
8
- v-if="url"
9
- target="_blank"
10
- :href="url"
11
- :class="valueClass"
12
- >
13
- <slot>{{ formattedValue }}</slot>
14
- </a>
7
+ <template v-if="url">
8
+ <a
9
+ v-if="!isLargeContent"
10
+ target="_blank"
11
+ :href="url"
12
+ >
13
+ <slot>{{ formattedValue }}</slot>
14
+ </a>
15
+ <template v-else>
16
+ <slot>{{ formattedValue }}</slot>
17
+ <a
18
+ target="_blank"
19
+ :href="url"
20
+ class="inline-block ml-2"
21
+ >
22
+ <LinkIcon class="w-4" />
23
+ </a>
24
+ </template>
25
+ </template>
15
26
  <template v-else>
16
27
  <slot>{{ formattedValue }}</slot>
17
28
  </template>
@@ -19,12 +30,13 @@
19
30
  </div>
20
31
  </template>
21
32
  <script setup lang="ts">
33
+ import { FaSolidLink as LinkIcon } from "danx-icon";
22
34
  import { computed } from "vue";
23
35
  import { fBoolean, fNumber } from "../../../../helpers";
24
36
 
25
37
  export interface LabelValueBlockProps {
26
38
  label: string;
27
- value: string | number | boolean;
39
+ value?: string | number | boolean;
28
40
  url?: string;
29
41
  dense?: boolean;
30
42
  nowrap?: boolean;
@@ -36,6 +48,7 @@ const props = withDefaults(defineProps<LabelValueBlockProps>(), {
36
48
  });
37
49
 
38
50
  const valueClass = computed(() => ({ "mt-2": !props.dense, "mt-1": props.dense, "text-no-wrap": props.nowrap }));
51
+ const isLargeContent = computed(() => typeof props.value === "string" && props.value.length > 30);
39
52
  const formattedValue = computed(() => {
40
53
  switch (typeof props.value) {
41
54
  case "boolean":
@@ -11,18 +11,11 @@
11
11
  import { useDebounceFn } from "@vueuse/core";
12
12
  import { nextTick, ref, watch } from "vue";
13
13
  import { fNumber } from "../../../../helpers";
14
- import { AnyObject, TextFieldProps } from "../../../../types";
14
+ import { AnyObject, NumberFieldProps } from "../../../../types";
15
15
  import TextField from "./TextField";
16
16
 
17
17
  const emit = defineEmits(["update:model-value", "update"]);
18
18
 
19
- export interface NumberFieldProps extends TextFieldProps {
20
- precision?: number;
21
- delay?: number;
22
- currency?: boolean;
23
- min?: number;
24
- max?: number;
25
- }
26
19
 
27
20
  const props = withDefaults(defineProps<NumberFieldProps>(), {
28
21
  modelValue: "",
@@ -144,6 +144,9 @@ export function fElapsedTime(start: string, end?: string) {
144
144
  * Formats an amount into USD currency format
145
145
  */
146
146
  export function fCurrency(amount: number, options?: object) {
147
+ if (amount === null || amount === undefined || isNaN(amount)) {
148
+ return "$-";
149
+ }
147
150
  return new Intl.NumberFormat("en-US", {
148
151
  style: "currency",
149
152
  currency: "USD",
@@ -179,6 +182,9 @@ export function fShortCurrency(value: string | number, options?: { round: boolea
179
182
  * Formats a number into a shorthand human-readable format (ie: 1.2M or 5K)
180
183
  */
181
184
  export function fShortNumber(value: string | number, options?: { round: boolean }) {
185
+ if (value === "" || value === null || value === undefined) {
186
+ return "-";
187
+ }
182
188
  const shorts = [
183
189
  { pow: 3, unit: "K" },
184
190
  { pow: 6, unit: "M" },
@@ -1,9 +1,19 @@
1
1
  import { uid } from "quasar";
2
2
  import { ShallowReactive, shallowReactive } from "vue";
3
3
  import { TypedObject } from "../types";
4
+ import { FlashMessages } from "./FlashMessages";
4
5
 
5
6
  const store = new Map<string, any>();
6
7
 
8
+ export function storeObjects<T extends TypedObject>(newObjects: T[]) {
9
+ for (const index in newObjects) {
10
+ if (newObjects[index] && typeof newObjects[index] === "object") {
11
+ newObjects[index] = storeObject(newObjects[index]);
12
+ }
13
+ }
14
+ return newObjects;
15
+ }
16
+
7
17
  /**
8
18
  * Store an object in the object store via type + id
9
19
  * Returns the stored object that should be used instead of the passed object as the returned object is shared across the system
@@ -56,3 +66,21 @@ export function storeObject<T extends TypedObject>(newObject: T): ShallowReactiv
56
66
  store.set(objectKey, reactiveObject);
57
67
  return reactiveObject;
58
68
  }
69
+
70
+ export async function autoRefreshObject<T extends TypedObject>(object: T, condition: (object: T) => boolean, callback: (object: T) => Promise<T>, interval = 3000) {
71
+ if (!object?.id || !object?.__type) {
72
+ throw new Error("Invalid stored object. Cannot auto-refresh");
73
+ }
74
+
75
+ if (condition(object)) {
76
+ const refreshedObject = await callback(object);
77
+
78
+ if (!refreshedObject.id) {
79
+ return FlashMessages.error(`Failed to refresh ${object.__type} (${object.id}) status: ` + object.name);
80
+ }
81
+
82
+ storeObject(refreshedObject);
83
+ }
84
+
85
+ setTimeout(() => autoRefreshObject(object, condition, callback), interval);
86
+ }
@@ -3,7 +3,7 @@ import { ListControlsRoutes } from "../types";
3
3
  import { downloadFile } from "./downloadPdf";
4
4
  import { request } from "./request";
5
5
 
6
- export function useActionRoutes(baseUrl: string): ListControlsRoutes {
6
+ export function useActionRoutes(baseUrl: string, extend?: object): ListControlsRoutes {
7
7
  return {
8
8
  list(pager?) {
9
9
  return request.post(`${baseUrl}/list`, pager);
@@ -33,6 +33,7 @@ export function useActionRoutes(baseUrl: string): ListControlsRoutes {
33
33
  },
34
34
  export(filter, name) {
35
35
  return downloadFile(`${baseUrl}/export`, name || "export.csv", { filter });
36
- }
36
+ },
37
+ ...extend
37
38
  };
38
39
  }
@@ -19,3 +19,11 @@ export interface TextFieldProps {
19
19
  readonly?: boolean;
20
20
  debounce?: string | number;
21
21
  }
22
+
23
+ export interface NumberFieldProps extends TextFieldProps {
24
+ precision?: number;
25
+ delay?: number;
26
+ currency?: boolean;
27
+ min?: number;
28
+ max?: number;
29
+ }