Remix.run blog tutorial - optimistic UI - remix

I'm following the blog tutorial on the remix.run example page and I'm struggling with the Optimistic UI aspect of it and failing to find any examples online
As you can see in my github repo I am trying to render the <PostAdmin /> route, but it's not loading for some reason.
import PostAdmin from "~/routes/posts/admin";
export default function NewPost() {
const errors = useActionData();
const transition = useTransition();
const isCreating = Boolean(transition.submission);
const title = transition?.submission?.formData?.get("title");
return isCreating ? (
<>
<PostAdmin />
</>
) : (
....
My original plan was to pass some additional items in here so I can render to the sidebar optimistically like the following. However I can't get the PostAdmin route to load at all, with the error Cannot destructure property 'posts' of 'useLoaderData(...)' as it is undefined.
export default function PostAdmin({
newPost,
}: {
newPost?: { title: string; slug: string };
}) {
As a side note, it's rendering the nested AdminIndex ok when I try that, but this would not achieve the homework example in the remix tasks as I need to pass it to the sidebar.
Hard one to explain and I imagine someone who's done the tasks before or has a solid example of Remix will understand. It may be that I am approaching this incorrectly. I have struggled to find complete examples anywhere.

Related

SMART on FHIR JavaScript API does not return JSON with out additional call to fetchAll for Observation in Cerner tutorial

I'm working on creating a SMART on FHIR application based on the Cerner tutorial at https://engineering.cerner.com/smart-on-fhir-tutorial/.
The following is called in example-smart-app.js
var patient = smart.patient;
var pt = patient.read();
var obv = smart.patient.api.fetchAll({
type: 'Observation',
query: {
code: {
$or: ['http://loinc.org|8302-2', 'http://loinc.org|8462-4',
'http://loinc.org|8480-6', 'http://loinc.org|2085-9',
'http://loinc.org|2089-1', 'http://loinc.org|55284-4']
}
}
});
I've modified slightly to the following:
<script>
fhirOnReady = function(smart) {
patient = smart.patient;
pt = patient.read();
var obv = smart.patient.api.fetchAll({
type: 'Observation',
query: {
code: {
$or: [
'http://loinc.org|8302-2',
'http://loinc.org|8462-4',
'http://loinc.org|8480-6',
'http://loinc.org|2085-9',
'http://loinc.org|2089-1',
'http://loinc.org|55284-4'
]
}
}
});
var populatePatientData = function(patient) {
$("#fname").html(patient.name[0].given);
$("#lname").html(patient.name[0].family);
$("#gender").html(patient.gender);
$("#dob").html(patient.birthDate);
}
$.when(pt, obv).fail(fhirOnError);
$.when(pt, obv).done(
function(patient, obv) {
populatePatientData(patient);
$("#patientJson").html(JSON.stringify(patient,undefined,2));
$("#patientSuccessMsg").html("<h1>Congratulations, you've also successfully loaded a patient using SMART on FHIR</h1>");
}
);
};
fhirOnError = function() {
$("#patientJson").html("An error occurred.\nThis is expected if you are looking at this page from a browser.");
};
FHIR.oauth2.ready(fhirOnReady, fhirOnError);
</script>
If I run the above using the SMART App Launcher at https://launch.smarthealthit.org/ everything seems to work as expected.
However, if I remove the call to smart.patient.api.fetchAll for the observations the patient JSON string is empty.
What is the correct way to get the entire patient resource using the SMART on FHIR JavaScript Library described at http://docs.smarthealthit.org/client-js/?
---EDIT ----------------------------------
If I try to implement using the code in the documentation at http://docs.smarthealthit.org/client-js/#smart-api I get the error shown below.
Code
<!-- index.html -->
<script src="./node_module/fhirclient/build/fhir-client.js"></script>
<script>
FHIR.oauth2.ready()
.then(client => client.request("Patient"))
.then(console.log)
.catch(console.error);
</script>
Error
Libraries are taken directly from the Cerner tutorial.
SMART apps usually have a "patient" in context that is already part of the data passed over to the system from which you are trying to elicit information. In this case you are trying to hit the Cerner FHIR server to get the observations linked to that Patient. Two things are possible at this point:
The Server may not have the Patient resource, which is why it is using the Id of the patient to fetch all observations
Check your smart SCOPEs, you may not be allowed to read Patient records in it's entirety.
Usually the FHIR endpoint can be deciphered using Fiddler following the launch sequence. As per the SMART exchange the CapabilityStatement is queried for the authorization and Token endpoints. If you are able to see the server then you can tack on the /Patient/id to get the resource but this means you have to have a valid token and the appropriate scope statements in place.

get image from backend api and display in angular

I want display image in angularV10 and get it from backend and I don't know why image not display and got error I'm looking for how to solve but I don't get answer
please can someone guide me
back-end:
get_image:async(req,res,next)=>{
Image.findAll().then(data=>{
res.send(data)
}) }
api:
router.get("/get_image",uploadController.get_image)
Front-end Angular : service.ts
get_file(): Observable<any>{
return this.http.get(baseUrl + '/get_image' , { responseType: 'Blob' as 'json' })}
code:
createImageFromBlob(image: Blob) {
let reader = new FileReader();
reader.addEventListener("load", () => {
this.imageToShow = reader.result; <<< this.imageToShow
}, false);
if (image) {
reader.readAsDataURL(image);
console.log(image)
}
}
get_image():void{
this.AddFileService.get_file().subscribe(data=>{
this.createImageFromBlob(data);
console.log(data)
})}
html:
<img [src]="imageToShow "/>
Error :
big error
unsafe:data:application/json;base64, ..... alot of chars i don't under stand
Not much in the way of detail to this, but hopefully I can at least clear some things up for you so that you can find your footing with the issue a little better.
The lot of characters you don't understand are the base64 encoded string of the image (if your code is producing an image, appropriately, at least).
What you want to show as an image is a data URI and it looks much like you've shown:
data:image/jpeg;base64,[a lot of characters]
Depending on the actual image type, it might not be image/jpeg, it might be image/png, etc.
There's two things wrong with that final block you've shown:
unsafe:data:application/json;base64, ..... alot of chars i don't under stand
The first one, having now told you what it should look like, is that it thinks the data is application/json instead of the expected image/xyz. So your process for constructing that data URI is wrong somewhere.
I suspect it's where you are telling in your blob type is supposed to be json (thus, application/json):
get_file(): Observable<any>{
return this.http.get(baseUrl + '/get_image' , { responseType: 'Blob' as 'json' })}
The second is the clue to the main issue that you are really seeing: unsafe:....
In order to display images in Angular in this fashion, you need to put those URIs and whatnot through the DomSanitizer:
constructor(private readonly sanitizer: DomSanitizer) {}
public safeImage: SafeUrl;
private getImage(...): void {
const imageBase64String = this.createImageFromBlobOrSomething(...);
this.safeImage = this.sanitizer.bypassSecurityTrustUrl(imageBase64String);
}
And your template will then use safeImage instead:
<img [src]="safeImage"/>
That will stop the unsafe:... error, but then you'll find that you won't see an image, because the data URI is for application/json, instead of an image type, which you'll need to go ahead and fix.
Edit: My approach for multiple images is to save the images (if you want to keep the initial images for further usage/manipulation) or just only save the safe url version of them...
this.rawImages = data; // Wherever your images come from, and if you want to keep them...
this.safeImages = [];
this.rawImages.forEach((img) => {
this.safeImages.push(this.sanitizer.bypassSecurityTrustUrl(img));
});
Then instead of *ngForing the raw images themselves, do it over the safeImages array instead:
<div *ngFor="let safeUrl of safeImages">
<img [src]="safeUrl">
</div>
ok anyone use blob for any file image pdf is not good decide
the best solution i do upload image to backend and generate URL
this website is helpful if you use node.js here

Lighthouse GraphQL - How to return current_user in mutation resolver?

I have a situation where I'm writing a custom mutation resolver, and currently have to pass the current_user's ID from my frontend to be able to then perform a ::find on the User model. What would be ideal however, is to be able to use an instance of current_user so that I don't have to rely on passing over an ID to my GraphQL server.
I'm still fairly new to the world of Laravel and GraphQL in general, however I've been reading up on the Lighthouse docs that mention the #auth directive, and other StackOverflow answers that mention using auth('api')->user(), however that returns NULL for me. I should also mention that I'm using the lighthouse-graphql-passport-auth library for dealing with user authentication, if that makes any difference. Does anybody know how to access current_user?
public function __invoke($_, array $args)
{
// $user = \App\Models\User::find($args['id']); <--- not ideal
$user = auth('api')->user(); <--- returns NULL
var_dump($user);
foreach ($user->notifications as $notification) {
$notification->viewed = true;
$notification->save();
}
$notifications = $user->notifications->toArray();
return [
'status' => 'Success',
'notifications' => $notifications
];
}
I found an interesting part in the lighthouse-graphql-passport-auth docs that discuss setting a [global middleware][3] to insert the logged in user into the $context. This was exactly like what I needed, and after adding the line into the middleware section of lighthouse.php config as mentioned in the docs, I was able to use $context->user() to return the currently logged in user.

Hiding _all_ remote methods in loopback model

I'm using loopback 3.
I have this lines of codes in my model's js (survey.js):
let enabledRemoteMethods = []
Survey.sharedClass.methods().forEach(function(method) {
console.log(method.name, method.isStatic)
let matchingEnabledRemoteMethod = _.find(enabledRemoteMethods, {name: method.name});
if (!matchingEnabledRemoteMethod) {
Survey.disableRemoteMethodByName(method.name, method.isStatic);
}
});
It works.... almost. I could still see in the explorer the REST endpoint for "PATCH /surveys/{id}". My expectation is: there shouldn't be any REST endpoints listed in the explorer.
Then I examined the URL corresponding to that operation, it is:
http://localhost:3000/explorer/#!/Survey/Survey_prototype_patchAttributes
Which, according to the documentation, means that patchAttributes is a static method.
Then I cross checked with the output in the console... there it says: pathAttributes is not static.
Incosistency!
I even have tried adding this line:
Survey.disableRemoteMethodByName("patchAttributes", true);
Also
Survey.disableRemoteMethodByName("patchAttributes", false);
No luck.
Can someone confirm if it's a bug in loopback 3 (I don't know about loopback 2, haven't checked)? If it's a bug I wouldn't have to spend time on it and just wait until it gets fixed. But if it's not a bug, can someone point out what's missing in my code?
Thanks!
UPDATE: figured out how
With this line I'm able to get rid of it:
Survey.disableRemoteMethodByName("prototype.patchAttributes", true);
The second parameter doesn't seem to matter (you can put false as well). Not sure why though (I suppose it should've accepted true only).
This is my current solution:
let disabledPrototypesRemoteMethods = ['patchAttributes']
let enabledRemoteMethods = [
"create", "findById", "replaceById", "deleteById",
"replaceOrCreateQuestion"
]
Survey.sharedClass.methods().forEach(function(method) {
if (enabledRemoteMethods.indexOf(method.name) == -1) {
Survey.disableRemoteMethodByName(method.name);
}
if (disabledPrototypesRemoteMethods.indexOf(method.name) > -1) {
Survey.disableRemoteMethodByName("prototype." + method.name);
}
});
Still, one small detail: this thing still shows up (I suppose it provides the POST alternative for the normal PUT for the replaceById operation..., but I don't want it; I want to force user of my API to go with the PUT only):
http://localhost:3000/explorer/#!/Survey/Survey_replaceById_post_surveys_id_replace
I tried adding this line:
Survey.disableRemoteMethodByName("replaceById_post_surveys_id_replace");
No luck.
Anyway... hope this useful for others; loopback doc is kind of sketchy.
You can get the prototype methods as well by looking at the stringName property. That way you can include the prototypes in your list.
The stringName includes the sharedClass name in the value, so you will need to parse that out.
module.exports = BusinessProfileContacted => {
const enabledRemoteMethods = ["create", "findById", "replaceById", "deleteById", "replaceOrCreateQuestion", "prototype.replaceAttributes"];
Survey.sharedClass.methods().forEach(method => {
const methodName = method.stringName.replace(/.*?(?=\.)/, '').substr(1);
if (enabledRemoteMethods.indexOf(methodName) === -1) {
Survey.disableRemoteMethodByName(methodName);
}
});
};

The right pattern for returning pagination data with the ember-data RESTAdapter?

I'm displaying a list of articles in a page that are fetched using the Ember Data RESTAdapter. I need to implement a bootstrap'esque paginator (see: http://twitter.github.com/bootstrap/components.html#pagination) and cant seem to find a sane pattern for returning pagination data such as, page count, article count, current page, within a single request.
For example, I'd like the API to return something like:
{
articles: [{...}, {...}],
page: 3,
article_count: 4525,
per_page: 20
}
One idea was to add an App.Paginator DS.Model so the response could look like:
{
articles: [{...}, {...}],
paginator: {
page: 3,
article_count: 4525,
per_page: 20
}
}
But this seems like overkill to hack together for something so trivial. Has anyone solved this problem or found a particular pattern they like? Is there a simple way to manage the RESTAdapter mappings to account for scenarios such as this?
Try to use Ember Pagination Support Mixin and provide your own implementation of the following method. Instead of loading all the content, you can fetch the required content when the user is navigating the pages. All what you need initially is the total account of your records.
didRequestRange: function(rangeStart, rangeStop) {
var content = this.get('fullContent').slice(rangeStart, rangeStop);
this.replace(0, this.get('length'), content);
}
With ember-data-beta3 you can pass a meta-property in your result. The default RESTSerializer looks for that property and stores it.
You can access the meta-data like this:
var meta = this.get("store").metadataFor("post");
If you are not able to change the JSON returned from the server you could override the extractMeta-hook on the ApplicationSerializer (or any other Model-specific serializer).
App.ApplicationSerializer = DS.RESTSerializer.extend({
extractMeta: function(store, type, payload) {
if (payload && payload.total) {
store.metaForType(type, { total: payload.total }); // sets the metadata for "post"
delete payload.total; // keeps ember data from trying to parse "total" as a record
}
}
});
Read more about meta-data here

Resources