Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Bertrand PINEL
ember-aws-ehipster
Commits
abb810e5
Commit
abb810e5
authored
Nov 27, 2018
by
Bertrand PINEL
Browse files
Add delete feature
parent
c5ba9d52
Changes
11
Hide whitespace changes
Inline
Side-by-side
addon/components/delete-row.js
0 → 100644
View file @
abb810e5
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
addon/styles/ember-aws-ehipster.css
0 → 100644
View file @
abb810e5
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
addon/templates/components/delete-row.hbs
0 → 100644
View file @
abb810e5
<button
class=
"btn btn-default"
onclick=
{{
action
"sendAction"
"delete"
record
}}
>
Delete
</button>
app/components/delete-row.js
0 → 100644
View file @
abb810e5
export
{
default
}
from
'
ember-aws-ehipster/components/delete-row
'
;
\ No newline at end of file
blueprints/ember-aws-ehipster/index.js
View file @
abb810e5
...
...
@@ -33,6 +33,12 @@ module.exports = {
"
\t
return usingProxyArg || hasGeneratedProxies;
\n
}
\n
"
;
addLineToFile
(
this
,
configPath
,
/'use strict';/
,
proxy
);
addLineToFile
(
this
,
configPath
,
/when it is created/
,
"
\t\t
proxy: 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
'
);
}
};
...
...
blueprints/entity-factory/files/__root__/controllers/entity-factory/__name__.js
View file @
abb810e5
...
...
@@ -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
blueprints/entity-factory/files/__root__/templates/entity-factory/__name__.hbs
View file @
abb810e5
...
...
@@ -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
...
...
blueprints/entity-factory/index.js
View file @
abb810e5
...
...
@@ -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\t
this.get('/
"
+
inflection
.
pluralize
(
entityName
)
+
"
', '
"
+
inflection
.
pluralize
(
entityName
)
+
"
');
\n
"
+
let
configLine
=
"
\t\t
this.get('/
"
+
inflection
.
pluralize
(
entityName
)
+
"
');
\n
"
+
"
\t\t
this.get('/
"
+
inflection
.
pluralize
(
entityName
)
+
"
/:id');
\n
"
+
"
\t\t
this.delete('/
"
+
inflection
.
pluralize
(
entityName
)
+
"
/:id');
\n
"
+
"
\t\t
this.patch('/
"
+
inflection
.
pluralize
(
entityName
)
+
"
/:id');
\n
"
+
"
\t\t
this.post('/
"
+
inflection
.
pluralize
(
entityName
)
+
"
');
"
;
if
(
!
fs
.
existsSync
(
mirageConfigPath
))
{
this
.
ui
.
writeLine
(
"
Creating file
"
+
mirageConfigPath
);
...
...
cloud/lambda-jsonapi.js
View file @
abb810e5
...
...
@@ -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
);};
...
...
package.json
View file @
abb810e5
{
"name"
:
"ember-aws-ehipster"
,
"version"
:
"0.1.
1
"
,
"version"
:
"0.1.
4
"
,
"description"
:
"The default blueprint for ember-cli addons."
,
"keywords"
:
[
"ember-addon"
...
...
tests/integration/components/delete-row-test.js
0 → 100644
View file @
abb810e5
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
'
);
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment