mirror of
https://github.com/directus/directus.git
synced 2026-02-07 00:35:03 -05:00
Merge branch 'main' of https://github.com/directus/directus into main
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "directus",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"license": "GPL-3.0-only",
|
||||
"homepage": "https://github.com/directus/directus#readme",
|
||||
"description": "Directus is a real-time API and App dashboard for managing SQL database content.",
|
||||
|
||||
@@ -7,7 +7,7 @@ import formatTitle from '@directus/format-title';
|
||||
import env from '../env';
|
||||
import axios from 'axios';
|
||||
import Joi from 'joi';
|
||||
import { InvalidPayloadException, ForbiddenException } from '../exceptions';
|
||||
import { InvalidPayloadException, ForbiddenException, FailedValidationException } from '../exceptions';
|
||||
import url from 'url';
|
||||
import path from 'path';
|
||||
import useCollection from '../middleware/use-collection';
|
||||
@@ -218,6 +218,60 @@ router.get(
|
||||
respond
|
||||
);
|
||||
|
||||
router.patch(
|
||||
'/',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const service = new FilesService({
|
||||
accountability: req.accountability,
|
||||
schema: req.schema,
|
||||
});
|
||||
|
||||
if (Array.isArray(req.body)) {
|
||||
const primaryKeys = await service.update(req.body);
|
||||
|
||||
try {
|
||||
const result = await service.readByKey(primaryKeys, req.sanitizedQuery);
|
||||
res.locals.payload = { data: result || null };
|
||||
} catch (error) {
|
||||
if (error instanceof ForbiddenException) {
|
||||
return next();
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
const updateSchema = Joi.object({
|
||||
keys: Joi.array().items(Joi.alternatives(Joi.string(), Joi.number())).required(),
|
||||
data: Joi.object().required().unknown(),
|
||||
});
|
||||
|
||||
const { error } = updateSchema.validate(req.body);
|
||||
|
||||
if (error) {
|
||||
throw new FailedValidationException(error.details[0]);
|
||||
}
|
||||
|
||||
const primaryKeys = await service.update(req.body.data, req.body.keys);
|
||||
|
||||
try {
|
||||
const result = await service.readByKey(primaryKeys, req.sanitizedQuery);
|
||||
res.locals.payload = { data: result || null };
|
||||
} catch (error) {
|
||||
if (error instanceof ForbiddenException) {
|
||||
return next();
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
return next();
|
||||
}),
|
||||
respond
|
||||
);
|
||||
|
||||
router.patch(
|
||||
'/:pk',
|
||||
multipartHandler,
|
||||
|
||||
@@ -151,7 +151,7 @@ export class ServerService {
|
||||
checks[`${client}:responseTime`][0].observedValue = +(endTime - startTime).toFixed(3);
|
||||
|
||||
if (
|
||||
checks[`${client}:responseTime`][0].observedValue! > 50 &&
|
||||
checks[`${client}:responseTime`][0].observedValue! > 150 &&
|
||||
checks[`${client}:responseTime`][0].status !== 'error'
|
||||
) {
|
||||
checks[`${client}:responseTime`][0].status = 'warn';
|
||||
@@ -205,7 +205,7 @@ export class ServerService {
|
||||
const endTime = performance.now();
|
||||
checks['cache:responseTime'][0].observedValue = +(endTime - startTime).toFixed(3);
|
||||
|
||||
if (checks['cache:responseTime'][0].observedValue > 50 && checks['cache:responseTime'][0].status !== 'error') {
|
||||
if (checks['cache:responseTime'][0].observedValue > 150 && checks['cache:responseTime'][0].status !== 'error') {
|
||||
checks['cache:responseTime'][0].status = 'warn';
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ export class ServerService {
|
||||
checks['rateLimiter:responseTime'][0].observedValue = +(endTime - startTime).toFixed(3);
|
||||
|
||||
if (
|
||||
checks['rateLimiter:responseTime'][0].observedValue > 50 &&
|
||||
checks['rateLimiter:responseTime'][0].observedValue > 150 &&
|
||||
checks['rateLimiter:responseTime'][0].status !== 'error'
|
||||
) {
|
||||
checks['rateLimiter:responseTime'][0].status = 'warn';
|
||||
@@ -281,7 +281,7 @@ export class ServerService {
|
||||
checks[`storage:${location}:responseTime`][0].observedValue = +(endTime - startTime).toFixed(3);
|
||||
|
||||
if (
|
||||
checks[`storage:${location}:responseTime`][0].observedValue! > 500 &&
|
||||
checks[`storage:${location}:responseTime`][0].observedValue! > 750 &&
|
||||
checks[`storage:${location}:responseTime`][0].status !== 'error'
|
||||
) {
|
||||
checks[`storage:${location}:responseTime`][0].status = 'warn';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/app",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"private": false,
|
||||
"description": "Directus is an Open-Source Headless CMS & API for Managing Custom Databases",
|
||||
"author": "Rijk van Zanten <rijk@rngr.org>",
|
||||
|
||||
@@ -5,7 +5,7 @@ import Vue from 'vue';
|
||||
import { isEqual } from 'lodash';
|
||||
import { Filter } from '@/types/';
|
||||
import filtersToQuery from '@/utils/filters-to-query';
|
||||
import { orderBy } from 'lodash';
|
||||
import { orderBy, throttle } from 'lodash';
|
||||
import moveInArray from '@/utils/move-in-array';
|
||||
|
||||
type Query = {
|
||||
@@ -91,7 +91,7 @@ export function useItems(collection: Ref<string>, query: Query) {
|
||||
}
|
||||
});
|
||||
|
||||
watch([filters, limit, searchQuery], async (after, before) => {
|
||||
watch([filters, limit], async (after, before) => {
|
||||
if (!before || isEqual(after, before)) {
|
||||
return;
|
||||
}
|
||||
@@ -102,6 +102,24 @@ export function useItems(collection: Ref<string>, query: Query) {
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
searchQuery,
|
||||
throttle(
|
||||
async (after, before) => {
|
||||
if (!before || isEqual(after, before)) {
|
||||
return;
|
||||
}
|
||||
page.value = 1;
|
||||
await Vue.nextTick();
|
||||
if (loading.value === false) {
|
||||
getItems();
|
||||
}
|
||||
},
|
||||
500,
|
||||
{ trailing: true }
|
||||
)
|
||||
);
|
||||
|
||||
return { itemCount, totalCount, items, totalPages, loading, error, changeManualSort, getItems };
|
||||
|
||||
async function getItems() {
|
||||
|
||||
@@ -27,7 +27,6 @@ export function usePreset(collection: Ref<string>, bookmark: Ref<number | null>
|
||||
const savePreset = async (preset?: Partial<Preset>) => {
|
||||
busy.value = true;
|
||||
const updatedValues = await presetsStore.savePreset(preset ? preset : localPreset.value);
|
||||
initLocalPreset();
|
||||
localPreset.value.id = updatedValues.id;
|
||||
busy.value = false;
|
||||
return updatedValues;
|
||||
@@ -35,7 +34,6 @@ export function usePreset(collection: Ref<string>, bookmark: Ref<number | null>
|
||||
|
||||
const saveLocal = () => {
|
||||
presetsStore.saveLocal(localPreset.value);
|
||||
initLocalPreset();
|
||||
};
|
||||
|
||||
const clearLocalSave = async () => {
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #append>
|
||||
<v-icon class="deselect" name="close" v-if="file" @click.stop="$emit('input', null)" />
|
||||
<template v-if="file">
|
||||
<v-icon name="open_in_new" class="edit" v-tooltip="$t('edit')" @click.stop="editDrawerActive = true" />
|
||||
<v-icon class="deselect" name="close" @click.stop="$emit('input', null)" v-tooltip="$t('deselect')" />
|
||||
</template>
|
||||
<v-icon v-else name="attach_file" />
|
||||
</template>
|
||||
</v-input>
|
||||
@@ -67,6 +70,15 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<drawer-item
|
||||
v-if="!disabled && file"
|
||||
:active.sync="editDrawerActive"
|
||||
collection="directus_files"
|
||||
:primary-key="file.id"
|
||||
:edits="edits"
|
||||
@input="stageEdits"
|
||||
/>
|
||||
|
||||
<v-dialog :active="activeDialog === 'upload'" @esc="activeDialog = null" @toggle="activeDialog = null">
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('upload_from_device') }}</v-card-title>
|
||||
@@ -118,18 +130,19 @@ import readableMimeType from '@/utils/readable-mime-type';
|
||||
import { getRootPath } from '@/utils/get-root-path';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { addTokenToURL } from '@/api';
|
||||
import DrawerItem from '../../views/private/components/drawer-item';
|
||||
|
||||
type FileInfo = {
|
||||
id: number;
|
||||
id: string;
|
||||
title: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { DrawerCollection },
|
||||
components: { DrawerCollection, DrawerItem },
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
type: [String, Object],
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
@@ -148,7 +161,10 @@ export default defineComponent({
|
||||
return readableMimeType(file.value.type, true);
|
||||
});
|
||||
|
||||
const assetURL = computed(() => getRootPath() + `assets/${props.value}`);
|
||||
const assetURL = computed(() => {
|
||||
const id = typeof props.value === 'string' ? props.value : (props.value as Record<string, any>)?.id;
|
||||
return getRootPath() + `assets/${id}`;
|
||||
});
|
||||
|
||||
const imageThumbnail = computed(() => {
|
||||
if (file.value === null || props.value === null) return null;
|
||||
@@ -158,8 +174,11 @@ export default defineComponent({
|
||||
return addTokenToURL(url);
|
||||
});
|
||||
|
||||
const { edits, stageEdits } = useEdits();
|
||||
const { url, isValidURL, loading: urlLoading, importFromURL } = useURLImport();
|
||||
|
||||
const editDrawerActive = ref(false);
|
||||
|
||||
return {
|
||||
activeDialog,
|
||||
setSelection,
|
||||
@@ -173,6 +192,9 @@ export default defineComponent({
|
||||
importFromURL,
|
||||
isValidURL,
|
||||
assetURL,
|
||||
editDrawerActive,
|
||||
edits,
|
||||
stageEdits,
|
||||
};
|
||||
|
||||
function useFile() {
|
||||
@@ -191,13 +213,22 @@ export default defineComponent({
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/files/${props.value}`, {
|
||||
const id = typeof props.value === 'string' ? props.value : (props.value as Record<string, any>)?.id;
|
||||
|
||||
const response = await api.get(`/files/${id}`, {
|
||||
params: {
|
||||
fields: ['title', 'type', 'filename_download'],
|
||||
fields: ['id', 'title', 'type', 'filename_download'],
|
||||
},
|
||||
});
|
||||
|
||||
file.value = response.data.data;
|
||||
if (props.value !== null && typeof props.value === 'object') {
|
||||
file.value = {
|
||||
...response.data.data,
|
||||
...props.value,
|
||||
};
|
||||
} else {
|
||||
file.value = response.data.data;
|
||||
}
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
@@ -255,6 +286,29 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useEdits() {
|
||||
const edits = computed(() => {
|
||||
// If the current value isn't a primitive, it means we've already staged some changes
|
||||
// This ensures we continue on those changes instead of starting over
|
||||
if (props.value && typeof props.value === 'object') {
|
||||
return props.value;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
return { edits, stageEdits };
|
||||
|
||||
function stageEdits(newEdits: Record<string, any>) {
|
||||
if (!file.value) return;
|
||||
|
||||
emit('input', {
|
||||
id: file.value.id,
|
||||
...newEdits,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -304,4 +358,12 @@ export default defineComponent({
|
||||
.deselect:hover {
|
||||
--v-icon-color: var(--danger);
|
||||
}
|
||||
|
||||
.edit {
|
||||
margin-right: 4px;
|
||||
|
||||
&:hover {
|
||||
--v-icon-color: var(--foreground-normal);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<v-button icon rounded :href="downloadSrc" :download="image.filename_download" v-tooltip="$t('download')">
|
||||
<v-icon name="get_app" />
|
||||
</v-button>
|
||||
<v-button icon rounded @click="editorActive = true" v-tooltip="$t('edit')">
|
||||
<v-icon name="crop_rotate" />
|
||||
<v-button icon rounded @click="editDrawerActive = true" v-tooltip="$t('edit')">
|
||||
<v-icon name="open_in_new" />
|
||||
</v-button>
|
||||
<v-button icon rounded @click="deselect" v-tooltip="$t('deselect')">
|
||||
<v-icon name="close" />
|
||||
@@ -31,12 +31,15 @@
|
||||
<div class="meta">{{ meta }}</div>
|
||||
</div>
|
||||
|
||||
<image-editor
|
||||
v-if="image && image.type.startsWith('image')"
|
||||
:id="image.id"
|
||||
@refresh="changeCacheBuster"
|
||||
v-model="editorActive"
|
||||
<drawer-item
|
||||
v-if="!disabled && image"
|
||||
:active.sync="editDrawerActive"
|
||||
collection="directus_files"
|
||||
:primary-key="image.id"
|
||||
:edits="edits"
|
||||
@input="stageEdits"
|
||||
/>
|
||||
|
||||
<file-lightbox v-model="lightboxActive" :id="image.id" />
|
||||
</div>
|
||||
<v-upload v-else @input="setImage" from-library from-url />
|
||||
@@ -54,6 +57,7 @@ import { nanoid } from 'nanoid';
|
||||
import { getRootPath } from '@/utils/get-root-path';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { addTokenToURL } from '@/api';
|
||||
import DrawerItem from '../../views/private/components/drawer-item';
|
||||
|
||||
type Image = {
|
||||
id: string; // uuid
|
||||
@@ -65,10 +69,10 @@ type Image = {
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { FileLightbox, ImageEditor },
|
||||
components: { FileLightbox, ImageEditor, DrawerItem },
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
type: [String, Object],
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
@@ -80,7 +84,7 @@ export default defineComponent({
|
||||
const loading = ref(false);
|
||||
const image = ref<Image | null>(null);
|
||||
const lightboxActive = ref(false);
|
||||
const editorActive = ref(false);
|
||||
const editDrawerActive = ref(false);
|
||||
|
||||
const cacheBuster = ref(nanoid());
|
||||
|
||||
@@ -114,43 +118,56 @@ export default defineComponent({
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(newID, oldID) => {
|
||||
if (newID === oldID) return;
|
||||
(newValue, oldValue) => {
|
||||
if (newValue === oldValue) return;
|
||||
|
||||
if (newID) {
|
||||
if (newValue) {
|
||||
fetchImage();
|
||||
}
|
||||
|
||||
if (oldID && newID === null) {
|
||||
if (oldValue && newValue === null) {
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const { edits, stageEdits } = useEdits();
|
||||
|
||||
return {
|
||||
loading,
|
||||
image,
|
||||
src,
|
||||
meta,
|
||||
lightboxActive,
|
||||
editorActive,
|
||||
editDrawerActive,
|
||||
changeCacheBuster,
|
||||
setImage,
|
||||
deselect,
|
||||
downloadSrc,
|
||||
edits,
|
||||
stageEdits,
|
||||
};
|
||||
|
||||
async function fetchImage() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/files/${props.value}`, {
|
||||
const id = typeof props.value === 'string' ? props.value : (props.value as Record<string, any>)?.id;
|
||||
|
||||
const response = await api.get(`/files/${id}`, {
|
||||
params: {
|
||||
fields: ['id', 'title', 'width', 'height', 'filesize', 'type', 'filename_download'],
|
||||
},
|
||||
});
|
||||
|
||||
image.value = response.data.data;
|
||||
if (props.value !== null && typeof props.value === 'object') {
|
||||
image.value = {
|
||||
...response.data.data,
|
||||
...props.value,
|
||||
};
|
||||
} else {
|
||||
image.value = response.data.data;
|
||||
}
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
@@ -173,7 +190,30 @@ export default defineComponent({
|
||||
loading.value = false;
|
||||
image.value = null;
|
||||
lightboxActive.value = false;
|
||||
editorActive.value = false;
|
||||
editDrawerActive.value = false;
|
||||
}
|
||||
|
||||
function useEdits() {
|
||||
const edits = computed(() => {
|
||||
// If the current value isn't a primitive, it means we've already staged some changes
|
||||
// This ensures we continue on those changes instead of starting over
|
||||
if (props.value && typeof props.value === 'object') {
|
||||
return props.value;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
return { edits, stageEdits };
|
||||
|
||||
function stageEdits(newEdits: Record<string, any>) {
|
||||
if (!image.value) return;
|
||||
|
||||
emit('input', {
|
||||
id: image.value.id,
|
||||
...newEdits,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import router from '@/router';
|
||||
import { getRootPath } from '@/utils/get-root-path';
|
||||
import { addTokenToURL } from '@/api';
|
||||
import { readableMimeType } from '../../../utils/readable-mime-type';
|
||||
|
||||
type File = {
|
||||
[key: string]: any;
|
||||
@@ -82,7 +83,7 @@ export default defineComponent({
|
||||
const type = computed(() => {
|
||||
if (!props.file || !props.file.type) return null;
|
||||
if (props.file.type.startsWith('image')) return null;
|
||||
return props.file.type.split('/')[1];
|
||||
return readableMimeType(props.file.type, true);
|
||||
});
|
||||
|
||||
const imageSource = computed(() => {
|
||||
|
||||
@@ -221,9 +221,7 @@ export default defineComponent({
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const { layout, layoutOptions, layoutQuery, filters, searchQuery, resetPreset } = usePreset(
|
||||
ref('directus_files')
|
||||
);
|
||||
const { layout, layoutOptions, layoutQuery, filters, searchQuery, resetPreset } = usePreset(ref('directus_files'));
|
||||
|
||||
const { confirmDelete, deleting, batchDelete, error: deleteError, batchEditActive } = useBatch();
|
||||
|
||||
@@ -412,9 +410,13 @@ export default defineComponent({
|
||||
|
||||
async function moveToFolder() {
|
||||
moving.value = true;
|
||||
|
||||
try {
|
||||
await api.patch(`/files/${selection.value}`, {
|
||||
folder: selectedFolder.value,
|
||||
await api.patch(`/files`, {
|
||||
keys: selection.value,
|
||||
data: {
|
||||
folder: selectedFolder.value,
|
||||
},
|
||||
});
|
||||
|
||||
selection.value = [];
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"application/x-freearc": "arc",
|
||||
"video/x-msvideo": "avi",
|
||||
"application/vnd.amazon.ebook": "azw",
|
||||
"application/octet-stream": "bin",
|
||||
"application/octet-stream": "file",
|
||||
"image/bmp": "bmp",
|
||||
"application/x-bzip": "bz",
|
||||
"application/x-bzip2": "bz2",
|
||||
@@ -12,6 +12,7 @@
|
||||
"text/css": "css",
|
||||
"text/csv": "csv",
|
||||
"application/msword": "doc",
|
||||
"application/sql": "sql",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
||||
"application/vnd.ms-fontobject": "eot",
|
||||
"application/epub+zip": "epub",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"application/x-shockwave-flash": "Adobe Flash",
|
||||
"application/vnd.adobe.fxp": "Adobe Flex Project",
|
||||
"application/pdf": "PDF",
|
||||
"application/sql": "SQL",
|
||||
"application/vnd.cups-ppd": "Adobe PostScript Printer Description File Format",
|
||||
"application/x-director": "Adobe Shockwave Player",
|
||||
"application/vnd.adobe.xdp+xml": "Adobe XML Data Package",
|
||||
|
||||
@@ -106,9 +106,8 @@ export default defineComponent({
|
||||
|
||||
const showDivider = computed(() => {
|
||||
return (
|
||||
fieldsStore
|
||||
.getFieldsForCollection(props.collection)
|
||||
.filter((field: Field) => field.meta?.hidden !== true).length > 0
|
||||
fieldsStore.getFieldsForCollection(props.collection).filter((field: Field) => field.meta?.hidden !== true)
|
||||
.length > 0
|
||||
);
|
||||
});
|
||||
|
||||
@@ -243,9 +242,7 @@ export default defineComponent({
|
||||
const relations = relationsStore.getRelationsForField(props.collection, props.junctionField);
|
||||
|
||||
const relationForField = relations.find((relation: Relation) => {
|
||||
return (
|
||||
relation.many_collection === props.collection && relation.many_field === props.junctionField
|
||||
);
|
||||
return relation.many_collection === props.collection && relation.many_field === props.junctionField;
|
||||
});
|
||||
|
||||
if (relationForField.one_collection) return relationForField.one_collection;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from '@vue/composition-api';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -34,7 +33,7 @@ export default defineComponent({
|
||||
}
|
||||
});
|
||||
|
||||
const emitValue = debounce((event: InputEvent) => emit('input', (event.target as HTMLInputElement).value), 850);
|
||||
const emitValue = (event: InputEvent) => emit('input', (event.target as HTMLInputElement).value);
|
||||
|
||||
return { active, disable, input, emitValue, emptyAndClose };
|
||||
|
||||
|
||||
2
docs/package-lock.json
generated
2
docs/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/docs",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@directus/docs",
|
||||
"private": false,
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"docs",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"command": {
|
||||
"bootstrap": {
|
||||
"npmClientArgs": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-directus-project",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"description": "A small installer util that will create a directory, add boilerplate folders, and install Directus through npm.",
|
||||
"main": "lib/index.js",
|
||||
"bin": "./lib/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/format-title",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"description": "Custom string formatter that converts any string into [Title Case](http://www.grammar-monster.com/lessons/capital_letters_title_case.htm)",
|
||||
"keywords": [
|
||||
"title-case",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/schema",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"description": "Utility for extracting information about existing DB schema",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -51,11 +51,11 @@ export default class MSSQL implements Schema {
|
||||
c.DATA_TYPE as data_type,
|
||||
pk.PK_SET as column_key
|
||||
FROM
|
||||
${this.knex.client.database()}.INFORMATION_SCHEMA.COLUMNS as c
|
||||
[${this.knex.client.database()}].INFORMATION_SCHEMA.COLUMNS as c
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
PK_SET = CASE WHEN CONSTRAINT_NAME LIKE '%pk%' THEN 'PRIMARY' ELSE NULL END
|
||||
FROM ${this.knex.client.database()}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
FROM [${this.knex.client.database()}].INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
) as pk
|
||||
ON [c].[TABLE_NAME] = [pk].[CONSTRAINT_TABLE_NAME]
|
||||
AND [c].[TABLE_CATALOG] = [pk].[CONSTRAINT_CATALOG]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/sdk-js",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"description": "The official Directus SDK for use in JavaScript!",
|
||||
"main": "dist/sdk-js.cjs.js",
|
||||
"module": "dist/sdk-js.bundler.js",
|
||||
|
||||
2
packages/specs/package-lock.json
generated
2
packages/specs/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/specs",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/specs",
|
||||
"version": "9.0.0-rc.30",
|
||||
"version": "9.0.0-rc.31",
|
||||
"description": "OpenAPI Specification of the Directus API",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user