Merge pull request #3702 from Budibase/duplicate-query

Duplicate queries
This commit is contained in:
Rory Powell 2021-12-08 11:32:28 +00:00 committed by GitHub
commit 83a28eb4bb
5 changed files with 134 additions and 6 deletions

View File

@ -11,6 +11,14 @@
await queries.delete(query)
notifications.success("Query deleted")
}
async function duplicateQuery() {
try {
await queries.duplicate(query)
} catch (e) {
notifications.error(e.message)
}
}
</script>
<ActionMenu>
@ -18,6 +26,7 @@
<Icon size="S" hoverable name="MoreSmallList" />
</div>
<MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
<MenuItem icon="Duplicate" on:click={duplicateQuery}>Duplicate</MenuItem>
</ActionMenu>
<ConfirmDialog

View File

@ -0,0 +1,50 @@
/**
* Duplicates a name with respect to a collection of existing names
* e.g.
* name all names result
* ------ ----------- --------
* ("foo") ["foo"] "foo (1)"
* ("foo") ["foo", "foo (1)"] "foo (2)"
* ("foo (1)") ["foo", "foo (1)"] "foo (2)"
* ("foo") ["foo", "foo (2)"] "foo (1)"
*
* Repl
*/
export const duplicateName = (name, allNames) => {
const baseName = name.split(" (")[0]
const isDuplicate = new RegExp(`${baseName}\\s\\((\\d+)\\)$`)
// get the sequence from matched names
const sequence = []
allNames.filter(n => {
if (n === baseName) {
return true
}
const match = n.match(isDuplicate)
if (match) {
sequence.push(parseInt(match[1]))
return true
}
return false
})
sequence.sort((a, b) => a - b)
// get the next number in the sequence
let number
if (sequence.length === 0) {
number = 1
} else {
// get the next number in the sequence
for (let i = 0; i < sequence.length; i++) {
if (sequence[i] !== i + 1) {
number = i + 1
break
}
}
if (!number) {
number = sequence.length + 1
}
}
return `${baseName} (${number})`
}

View File

@ -0,0 +1,42 @@
const { duplicateName } = require("../duplicate")
describe("duplicate", () => {
describe("duplicates a name ", () => {
it("with a single existing", async () => {
const names = ["foo"]
const name = "foo"
const duplicate = duplicateName(name, names)
expect(duplicate).toBe("foo (1)")
})
it("with multiple existing", async () => {
const names = ["foo", "foo (1)", "foo (2)"]
const name = "foo"
const duplicate = duplicateName(name, names)
expect(duplicate).toBe("foo (3)")
})
it("with mixed multiple existing", async () => {
const names = ["foo", "foo (1)", "foo (2)", "bar", "bar (1)", "bar (2)"]
const name = "foo"
const duplicate = duplicateName(name, names)
expect(duplicate).toBe("foo (3)")
})
it("with incomplete sequence", async () => {
const names = ["foo", "foo (2)", "foo (3)"]
const name = "foo"
const duplicate = duplicateName(name, names)
expect(duplicate).toBe("foo (1)")
})
})
})

View File

@ -1,14 +1,19 @@
import { writable, get } from "svelte/store"
import { datasources, integrations, tables, views } from "./"
import api from "builderStore/api"
import { duplicateName } from "../../helpers/duplicate"
const sortQueries = queryList => {
queryList.sort((q1, q2) => {
return q1.name.localeCompare(q2.name)
})
}
export function createQueriesStore() {
const { subscribe, set, update } = writable({ list: [], selected: null })
const store = writable({ list: [], selected: null })
const { subscribe, set, update } = store
return {
subscribe,
set,
update,
const actions = {
init: async () => {
const response = await api.get(`/api/queries`)
const json = await response.json()
@ -17,6 +22,7 @@ export function createQueriesStore() {
fetch: async () => {
const response = await api.get(`/api/queries`)
const json = await response.json()
sortQueries(json)
update(state => ({ ...state, list: json }))
return json
},
@ -49,6 +55,7 @@ export function createQueriesStore() {
} else {
queries.push(json)
}
sortQueries(queries)
return { list: queries, selected: json._id }
})
return json
@ -76,6 +83,27 @@ export function createQueriesStore() {
})
return response
},
duplicate: async query => {
let list = get(store).list
const newQuery = { ...query }
const datasourceId = query.datasourceId
delete newQuery._id
delete newQuery._rev
newQuery.name = duplicateName(
query.name,
list.map(q => q.name)
)
actions.save(datasourceId, newQuery)
},
}
return {
subscribe,
set,
update,
...actions,
}
}

View File

@ -6,7 +6,6 @@ jest.mock('builderStore/api');
import { SOME_QUERY, SAVE_QUERY_RESPONSE } from './fixtures/queries'
import { createQueriesStore } from "../queries"
import { datasources } from '../datasources'
describe("Queries Store", () => {
let store = createQueriesStore()