Commit abb810e5 authored by Bertrand PINEL's avatar Bertrand PINEL

Add delete feature

parent c5ba9d52
import Component from '@ember/component';
import {get} from '@ember/object';
import layout from '../templates/components/delete-row';
export default Component.extend({
layout,
sendAction: null,
record: null,
actions: {
sendAction(actionName, record, event) {
get(this, 'sendAction')(actionName, record);
event.stopPropagation();
}
}
});
\ No newline at end of file
a:hover {
text-decoration: none;
}
a.active {
font-weight: 700;
}
pre {
text-align: left;
white-space: pre-line;
}
.table-footer {
border: 1px solid #ddd;
padding: 5px 0;
}
.models-table-wrapper {
margin-bottom: 20px;
}
.btn-default {
background-image: none !important;
}
.columns-dropdown {
margin-bottom: 20px;
}
.table-column-options.table > tbody > tr > td {
border-top-width: 0;
}
tr.selected-row>td:not(.grouping-cell), tr.selected-expand>td:not(.grouping-cell) {
background: #C6E746;
}
.navbar-text.gh {
margin-top: 13px !important;
margin-bottom: 11px !important;
}
\ No newline at end of file
<button
class="btn btn-default"
onclick={{action "sendAction" "delete" record}}>
Delete
</button>
export { default } from 'ember-aws-ehipster/components/delete-row';
\ No newline at end of file
......@@ -33,6 +33,12 @@ module.exports = {
"\treturn usingProxyArg || hasGeneratedProxies;\n}\n";
addLineToFile(this, configPath, /'use strict';/, proxy);
addLineToFile(this, configPath, /when it is created/, "\t\tproxy: usingProxy(),");
// Add import of ember_aws_ehipster.css to apps.css
let stylePath = (options.dummy) ? "tests/dummy/app/styles/app.css" : "app/styles/app.css";
let importcss = "@import 'ember-aws-ehipster.css';\n";
let fileContents = importcss + fs.readFileSync(stylePath, 'utf-8');
fs.writeFileSync(stylePath, fileContents, 'utf-8');
}
};
......
......@@ -10,6 +10,10 @@ isAddingEntry: false,
var col = A([
<%=tableCols%>
]);
col.pushObject({
title: 'Delete',
component: 'delete-row'
});
return col;
}),
......@@ -25,6 +29,10 @@ actions: {
this.set('addEntryModal', false).then((entry) => {
console.log("new entry of id "+entry.get('id')+" created");
});
},
deleteRecord (record) {
console.log('record is '+ record);
record.destroyRecord();
}
}
});
\ No newline at end of file
......@@ -2,9 +2,12 @@
<div class="container-fluid">
<h2>List of <%=singularEntityName%> Entities</h2>
{{models-table
data=<%=singularEntityName%>TableContent
columns=<%=singularEntityName%>TableColumns}}
{{#models-table data=<%=singularEntityName%>TableContent columns=<%=singularEntityName%>TableColumns delete="deleteRecord" as |mt|}}
{{mt.global-filter}}
{{mt.table}}
{{mt.footer}}
{{/models-table}}
{{#bs-button onClick=(action (mut addEntryModal) true)}}
Add new entry
......
......@@ -161,7 +161,10 @@ module.exports = {
// Complete /mirage/config.js
let mirageConfigPath = (options.dummy) ? "tests/dummy/mirage/config.js" : "mirage/config.js";
let configLine = "\t\tthis.get('/"+inflection.pluralize(entityName)+"', '"+inflection.pluralize(entityName)+"');\n"+
let configLine = "\t\tthis.get('/"+inflection.pluralize(entityName)+"');\n"+
"\t\tthis.get('/"+inflection.pluralize(entityName)+"/:id');\n"+
"\t\tthis.delete('/"+inflection.pluralize(entityName)+"/:id');\n"+
"\t\tthis.patch('/"+inflection.pluralize(entityName)+"/:id');\n"+
"\t\tthis.post('/"+inflection.pluralize(entityName)+"');";
if (!fs.existsSync(mirageConfigPath)) {
this.ui.writeLine("Creating file "+mirageConfigPath);
......
......@@ -69,195 +69,201 @@ const EPOCH = 1300000000000;
// Instagram inspired --> https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c
function generateRowId(subid) {
var ts = new Date().getTime() - EPOCH; // limit to recent
// 41 bits for time in milliseconds (gives us 41 years of IDs with a custom epoch
var randid = Math.floor(Math.random() * 512);
ts = (ts * 64); // bit-shift << 6
// Given shard (if any...)
ts = ts + subid;
// random value
return (ts * 512) + (randid % 512);
}
const createObject = (obj) => {
let objout = { "type": obj.ObjectType,
"id": obj.Id,
"attributes": {},
"relationships": {}
};
for (var attr in obj) {
if (attr !== 'ObjectType' && attr !== 'Id') {
if(!attr.endsWith('_id')) {
objout.attributes[attr] = obj[attr];
} else {
let relationDetails = attr.split('_');
let relationId = Number(obj[attr]);
objout.relationships[relationDetails[0]] = {
"links": {
"self": "/"+obj.ObjectType+"/"+obj.Id+"/relationships/"+relationDetails[0],
"related": "/"+obj.ObjectType+"/"+obj.Id+"/"+relationDetails[0]
},
"data": {"type": relationDetails[1], "id": relationId}
};
// TODO what's about if relation is not a belongsTo but a hasMany...
}
}
}
return objout;
}
const createData = (data) => {
if (Array.isArray(data)) {
let outdata = [];
for (let i=0;i<data.length;i++){
outdata.push(createObject(data[i]));
}
return outdata;
} else {
return createObject(data);
}
}
const createRelationships = (data) => {
return {};
}
const createResponse = (statusCode, body) => {
return {
'statusCode': statusCode,
'data': createData(body),
'relationships': createRelationships(body)
}
};
const getMethod = (event, context, callback) => {
let params = {
TableName: tableName,
},
type = event.params.path.type,
id = Number(event.params.path.id),
dbGet = {};
if (id) {
params.Key = {
'ObjectType': type,
'Id': id
};
dbGet = (params) => { return dynamo.get(params).promise() };
console.log('EmberDataServerless lambda GET single value with params: ', params);
} else {
params.KeyConditionExpression = 'ObjectType = :objectType';
params.ExpressionAttributeValues = { ':objectType': type };
dbGet = (params) => { return dynamo.query(params).promise() };
console.log('EmberDataServerless lambda GET multiple values with params: ', params);
}
dbGet(params).then( (data) => {
console.log('EmberDataServerless lambda GET data received: ', data);
if (id && !data.Item) {
callback(null, createResponse(404, "ITEM NOT FOUND"));
return;
} else if (id && data.Item) {
console.log(`RETRIEVED ITEM SUCCESSFULLY WITH doc = ${data.Item}`);
callback(null, createResponse(200, data.Item));
} else {
console.log('SCANNING TABLE');
console.log(`RETRIEVED ITEMS SUCCESSFULLY WITH doc = ${data.Items}`);
callback(null, createResponse(200, data.Items));
}
}).catch( (err) => {
console.log(`GET ITEM FAILED FOR Entry = ${params}, WITH ERROR: ${err}`);
callback(null, createResponse(500, err));
});
};
const putMethod = (event, context, callback) => {
const body=event['body-json'];
const attrs = body.data.attributes;
const relations = body.data.relationships;
// Without any body content, there is nothing to put...
if (!body || !attrs) {
callback(null, createResponse(500, 'No content found in body'));
return;
}
// Retrieving the type and generating a new id for created item
let type = event.params.path.type,
id = generateRowId(1);
// Final content contains at least these two fields + the atributes
let content = {
"ObjectType": type,
"Id": id
};
// Adding attributes as column in dynamoDb
for (var prop in attrs) {
content[prop] = attrs[prop];
}
// Dealing with relationships if any
if (relations){
for (var relName in relations) {
let relData = relations[relName]["data"];
let newCol;
if (!Array.isArray(relData)) {
newCol = relName+'_'+relData["type"]+'_id';
content[newCol] = relData["id"];
} else {
for (var i=0; i<relData.length;i++){
let currentData = relData[i];
newCol = relName+'_'+currentData["type"]+'_id';
content[newCol] = currentData["id"];
}
}
}
}
const entry = {
TableName: 'EmberDataServerlessTable',
Item: content
};
console.log('Try saving entity of type '+type+' and content '+JSON.stringify(entry));
//let dbPut = (entry) => { return dynamo.put(entry).promise() };
dynamo.put(entry, function(err, data) {
if (err) {
console.log("Error", err);
callback(null, createResponse(500, 'Error '+err));
} else {
body.data.id = id;
body['statusCode'] = 200;
console.log(`PUT ITEM SUCCEEDED WITH data=`+JSON.stringify(body));
callback(null, body);
}
});
};
const deleteMethod = (event, context, callback) => {
let type = event.params.path.type,
id = Number(event.params.path.id),
params = {
'TableName': tableName,
'Key': {
'ObjectType': type,
'Id': id
},
'ReturnValues': 'ALL_OLD'
};
let dbDelete = (params) => { return dynamo.delete(params).promise() };
dbDelete(params).then( (data) => {
if (!data.Attributes) {
callback(null, createResponse(404, "ITEM NOT FOUND FOR DELETION"));
return;
}
console.log(`DELETED ITEM OF TYPE ${type} SUCCESSFULLY WITH id = ${id}`);
callback(null, createResponse(200,data));
}).catch( (err) => {
console.log(`DELETE ITEM OF TYPE ${type} FAILED FOR id = ${id}, WITH ERROR: ${err}`);
callback(null, createResponse(500, err));
});
};
var ts = new Date().getTime() - EPOCH; // limit to recent
// 41 bits for time in milliseconds (gives us 41 years of IDs with a custom epoch
var randid = Math.floor(Math.random() * 512);
ts = (ts * 64); // bit-shift << 6
// Given shard (if any...)
ts = ts + subid;
// random value
return (ts * 512) + (randid % 512);
}
const createObject = (obj) => {
let objout = { "type": obj.ObjectType,
"id": obj.Id,
"attributes": {},
"relationships": {}
};
for (var attr in obj) {
if (attr !== 'ObjectType' && attr !== 'Id') {
if(!attr.endsWith('_id')) {
objout.attributes[attr] = obj[attr];
} else {
let relationDetails = attr.split('_');
let relationId = Number(obj[attr]);
objout.relationships[relationDetails[0]] = {
"links": {
"self": "/"+obj.ObjectType+"/"+obj.Id+"/relationships/"+relationDetails[0],
"related": "/"+obj.ObjectType+"/"+obj.Id+"/"+relationDetails[0]
},
"data": {"type": relationDetails[1], "id": relationId}
};
// TODO what's about if relation is not a belongsTo but a hasMany...
}
} else {
objout[(attr==='ObjectType')?'type':'id'] = obj[attr];
}
}
console.log('Return object is '+JSON.stringify(objout));
return objout;
}
const createData = (data) => {
if (Array.isArray(data)) {
let outdata = [];
for (let i=0;i<data.length;i++){
outdata.push(createObject(data[i]));
}
return outdata;
} else {
return createObject(data);
}
}
const createRelationships = (data) => {
return {};
}
const createResponse = (statusCode, body) => {
console.log("Body is "+JSON.stringify(body));
return {
'statusCode': statusCode,
'data': createData(body),
'relationships': createRelationships(body)
}
};
const getMethod = (event, context, callback) => {
let params = {
TableName: tableName,
},
type = event.params.path.type,
id = Number(event.params.path.id),
dbGet = {};
if (id) {
params.Key = {
'ObjectType': type,
'Id': id
};
dbGet = (params) => { return dynamo.get(params).promise() };
console.log('EmberDataServerless lambda GET single value with params: ', params);
} else {
params.KeyConditionExpression = 'ObjectType = :objectType';
params.ExpressionAttributeValues = { ':objectType': type };
dbGet = (params) => { return dynamo.query(params).promise() };
console.log('EmberDataServerless lambda GET multiple values with params: ', params);
}
dbGet(params).then( (data) => {
console.log('EmberDataServerless lambda GET data received: ', data);
if (id && !data.Item) {
callback(null, createResponse(404, "ITEM NOT FOUND"));
return;
} else if (id && data.Item) {
console.log(`RETRIEVED ITEM SUCCESSFULLY WITH doc = ${data.Item}`);
callback(null, createResponse(200, data.Item));
} else {
console.log('SCANNING TABLE');
console.log(`RETRIEVED ITEMS SUCCESSFULLY WITH doc = ${data.Items}`);
callback(null, createResponse(200, data.Items));
}
}).catch( (err) => {
console.log(`GET ITEM FAILED FOR Entry = ${params}, WITH ERROR: ${err}`);
callback(null, createResponse(500, err));
});
};
const putMethod = (event, context, callback) => {
const body=event['body-json'];
const attrs = body.data.attributes;
const relations = body.data.relationships;
// Without any body content, there is nothing to put...
if (!body || !attrs) {
callback(null, createResponse(500, 'No content found in body'));
return;
}
// Retrieving the type and generating a new id for created item
let type = event.params.path.type,
id = generateRowId(1);
// Final content contains at least these two fields + the atributes
let content = {
"ObjectType": type,
"Id": id
};
// Adding attributes as column in dynamoDb
for (var prop in attrs) {
content[prop] = attrs[prop];
}
// Dealing with relationships if any
if (relations){
for (var relName in relations) {
let relData = relations[relName]["data"];
let newCol;
if (!Array.isArray(relData)) {
newCol = relName+'_'+relData["type"]+'_id';
content[newCol] = relData["id"];
} else {
for (var i=0; i<relData.length;i++){
let currentData = relData[i];
newCol = relName+'_'+currentData["type"]+'_id';
content[newCol] = currentData["id"];
}
}
}
}
const entry = {
TableName: 'EmberDataServerlessTable',
Item: content
};
console.log('Try saving entity of type '+type+' and content '+JSON.stringify(entry));
//let dbPut = (entry) => { return dynamo.put(entry).promise() };
dynamo.put(entry, function(err, data) {
if (err) {
console.log("Error", err);
callback(null, createResponse(500, 'Error '+err));
} else {
body.data.id = id;
body['statusCode'] = 200;
console.log(`PUT ITEM SUCCEEDED WITH data=`+JSON.stringify(body));
callback(null, body);
}
});
};
const deleteMethod = (event, context, callback) => {
let type = event.params.path.type,
id = Number(event.params.path.id),
params = {
'TableName': tableName,
'Key': {
'ObjectType': type,
'Id': id
},
'ReturnValues': 'ALL_OLD'
};
const body=event['body-json'];
let dbDelete = (params) => { return dynamo.delete(params).promise() };
dbDelete(params).then( (data) => {
if (!data.Attributes) {
callback(null, createResponse(404, "ITEM NOT FOUND FOR DELETION"));
return;
}
console.log(`DELETED ITEM OF TYPE ${type} SUCCESSFULLY WITH id = ${id}`);
callback(null, body);
}).catch( (err) => {
console.log(`DELETE ITEM OF TYPE ${type} FAILED FOR id = ${id}, WITH ERROR: ${err}`);
callback(null, createResponse(500, err));
});
};
const callback = (evt, msg) => {console.log(msg);};
......
{
"name": "ember-aws-ehipster",
"version": "0.1.1",
"version": "0.1.4",
"description": "The default blueprint for ember-cli addons.",
"keywords": [
"ember-addon"
......
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | delete-row', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`{{delete-row}}`);
assert.equal(this.element.textContent.trim(), '');
// Template block usage:
await render(hbs`
{{#delete-row}}
template block text
{{/delete-row}}
`);
assert.equal(this.element.textContent.trim(), 'template block text');
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment