Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update mapbox/assembly #200

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/db.rs
Expand Up @@ -97,3 +97,26 @@ impl DbReadWrite {
}
}
}

///
/// Return a JSON definition of the schema, including comments
///
pub fn meta(conn: &impl postgres::GenericConnection) -> Result<serde_json::Value, HecateError> {
match conn.query("
SELECT
table_name,
column_name,
data_type
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = 'geo'
OR TABLE_NAME = 'deltas'
", &[]) {
Ok(rows) => {
Ok(json!(false))
},
Err(err) => Err(HecateError::from_db(err))
}
}

2 changes: 1 addition & 1 deletion src/lib.rs
Expand Up @@ -596,7 +596,7 @@ fn user_self(

fn user_pwreset(
conn: web::Data<DbReadWrite>,
mut auth: auth::Auth,
auth: auth::Auth,
reset: Json<PwReset>
) -> Result<Json<serde_json::Value>, HecateError> {
// No auth rules here - user can always change their password
Expand Down
3 changes: 2 additions & 1 deletion web/package.json
Expand Up @@ -11,9 +11,10 @@
"dev": "NODE_ENV=development parcel index.html login/index.html --public-url='/admin/'"
},
"dependencies": {
"@mapbox/assembly": "^0.23.0",
"@mapbox/assembly": "^0.24.0",
"@mapbox/mapbox-gl-geocoder": "^4.1.2",
"@turf/turf": "^5.1.6",
"behave-js": "^1.5.0",
"moment": "^2.22.2",
"vue": "^2.5.16"
},
Expand Down
15 changes: 15 additions & 0 deletions web/src/main.js
Expand Up @@ -24,6 +24,21 @@ window.hecate = {
});
}
},
query: {
get: function(query, cb) {
fetch(`${window.location.protocol}//${window.location.host}/api/data/query?limit=100&query=${encodeURIComponent(query.replace(/;/g, ''))}`, {
method: 'GET',
credentials: 'same-origin'
}).then((response) => {
if (response.status !== 200) return cb(new Error(response.status + ':' + response.statusText));
return response.text();
}).then((response) => {
return cb(null, response);
}).catch((err) => {
return cb(err);
});
}
},
schema: {
get: function(cb) {
fetch(`${window.location.protocol}//${window.location.host}/api/schema`, {
Expand Down
85 changes: 49 additions & 36 deletions web/src/modals/Query.vue
Expand Up @@ -3,17 +3,32 @@
<div class='flex-parent flex-parent--center-main flex-parent--center-cross h-full' style="pointer-events:auto;">
<div class="flex-child px12 py12 w600 h400 bg-white round-ml shadow-darken10">
<div class='grid w-full'>
<template v-if='!results.length'>
<div class='pb12 col col--11'>
<h3 class='fl txt-m txt-bold fl'>SQL Query Editor</h3>
</div>
<div class='pb12 col col--12'>
<h3 class='fl txt-m txt-bold my6'>Database Query Tool</h3>

<button @click='close()' class='fr btn round bg-white color-black bg-darken25-on-hover h36'><svg class='icon'><use href='#icon-close'/></svg></button>

<div class='col col--1'>
<button @click='close()' class='fr btn round bg-white color-black bg-darken25-on-hover'><svg class='icon'><use href='#icon-close'/></svg></button>
<div v-if='!error' class="flex-parent-inline fr mx12">
<button class="btn btn--pill btn--stroke btn--pill-hl round">Table Definitions</button>
<button @click='results = ""' class="btn btn--pill btn--stroke btn--pill-hc round">Query Editor</button>
<button @click='getQuery' class="btn btn--pill btn--stroke btn--pill-hr round">Results</button>
</div>
</div>

<template v-if='error'>
<div class='col col--12'>
<svg class='mx-auto icon h60 w60 color-red'><use xlink:href='#icon-alert'/></svg>
</div>
<div class='col col--12 align-center'>
<span>There was an error performing that query</span>
</div>
<div class='col col--12 align-center py24'>
<button @click='errorConfirm' class='btn btn--stroke round btn--red'>Ok</button>
</div>
</template>
<template v-else-if='!results.length'>
<div class='col col--12'>
<textarea :readonly="!credentials.uid" class='textarea w-full h360' v-model="query" placeholder="Query SQL"></textarea>
<textarea id='editor' :readonly="!credentials.uid" class='textarea w-full h360' v-model="query" placeholder="Query SQL"></textarea>
</div>

<div class='col col--12'>
Expand All @@ -23,33 +38,15 @@
<div class='grid grid--gut12'>
<div class='col col--8 py12'></div>
<div class='col col--4 py12'>
<button @click="getQuery(query)" class='btn round btn--stroke w-full'>Query</button>
<button @click="getQuery" class='btn round btn--stroke w-full'>Query</button>
</div>
</div>
</div>
</template>
<template v-else>
<div class='pb12 col col--11'>
<button @click="results = ''" class='btn round bg-gray-light bg-darken25-on-hover color-gray-dark fl'><svg class='icon'><use href='#icon-arrow-left'/></button>
<h3 class='fl pl12 txt-m txt-bold fl'>SQL Results Viewer</h3>
</div>

<div class='col col--1'>
<button @click='close()' class='fr btn round bg-white color-black bg-darken25-on-hover color-gray-dark fl'><svg class='icon'><use href='#icon-arrow-left'/></button>
</div>

<div class='col col--12'>
<textarea readonly class='textarea w-full h360' v-model="results" placeholder="SQL Results"></textarea>
</div>

<div class='col col--12'>
<div class='grid grid--gut12'>
<div class='col col--8 py12'></div>
<div class='col col--4 py12'>
<button @click="close()" class='btn round btn--stroke w-full'>Close</button>
</div>
</div>
</div>
</template>
</div>
</div>
Expand All @@ -58,26 +55,42 @@
</template>

<script>
import Behave from 'behave-js';

export default {
name: 'query',
data: function() {
return {
query: '',
results: []
query: 'SELECT\n *\nFROM\n geo',
results: [],
editor: false,
error: false
}
},
mounted: function() {
this.editor = new Behave({
textarea: document.getElementById('editor'),
softTabs: false,
});
},
methods: {
close: function() {
this.$emit('close');
},
getQuery: function(query) {
fetch(`${window.location.protocol}//${window.location.host}/api/data/query?limit=100&query=${encodeURIComponent(this.query.replace(/;/g, ''))}`, {
method: 'GET',
credentials: 'same-origin'
}).then((response) => {
return response.text();
}).then((body) => {
this.results = body;
errorConfirm: function() {
this.results = '';
this.error = false;
},
getQuery: function() {
window.hecate.query.get(this.query, (err, results) => {
if (err) return this.error = true;

// Ensure the query result contains an End Of Transmission Character
if (results.substring(results.length - 1, results.length) === '\x04') {
this.results = results.substring(0, results.length - 1);
} else {
this.error = true;
}
});
}
},
Expand Down